В Java, если синхронный метод содержит вызов несинхронизированного, может ли другой метод по-прежнему одновременно обращаться к несинхронизированному методу? В основном, что я спрашиваю, все в синхронизированном методе имеет блокировку (включая вызовы для других синхронизированных методов)? Большое спасибо
Если синхронизированный метод вызывает другой несинхронизированный метод, существует ли блокировка несинхронизированного метода
Ответ 1
Если вы используете метод synchronized
, то вызовы других методов, которые также являются synchronized
другими потоками, блокируются. Однако вызовы несинхронизированных методов другими потоками не блокируются - каждый может вызвать их в одно и то же время.
public synchronized void someSynchronizedMethod() {
...
someNonSynchronizedMethod();
...
}
// anyone can call this method even if the someSynchronizedMethod() method has
// been called and the lock has been locked
public void someNonSynchronizedMethod() {
...
}
Кроме того, если вы вызываете someSynchronizedMethod()
, но находитесь в методе someNonSynchronizedMethod()
, вы все равно удерживаете блокировку. Блокировка включена, когда вы вводите синхронизированный блок и отключается при выходе из этого метода. Вы можете вызывать всевозможные другие несинхронизированные методы, и они все равно будут заблокированы.
Но вы задаете в своем вопросе две разные вещи:
В Java, если синхронный метод содержит вызов несинхронизированного, может ли другой метод по-прежнему одновременно обращаться к несинхронизированному методу?
Да. Другие методы могут получить доступ к несинхронизированным методам.
В основном, что я спрашиваю, все в синхронизированном методе имеет блокировку на нем (включая вызовы другим синхронизированным методам)?
Да, да. Другие вызовы синхронизированных методов блокируются. Но несинхронизированные методы не заблокированы.
Также помните, что если метод static
, то блокировка находится в объекте Class
в ClassLoader
.
// this locks on the Class object in the ClassLoader
public static synchronized void someStaticMethod() {
Если метод является методом экземпляра, то блокировка находится в экземпляре класса.
// this locks on the instance object that contains the method
public synchronized void someInstanceMethod() {
В этих двух случаях есть 2 разных замка.
Наконец, когда вы имеете дело с методами экземпляра synchronized
, каждый экземпляр класса является заблокированным. Это означает, что два потока могут быть в одном и том же методе synchronized
одновременно с разными экземплярами. Но если 2 потока пытаются работать с методами synchronized
в одном экземпляре, каждый будет блокироваться до тех пор, пока другой не выйдет из этого метода.
Ответ 2
Если поток A вызывает синхронизированный метод M1, который, в свою очередь, вызывает несинхронизированный метод M2, тогда поток B все равно может вызывать M2 без блокировки.
Синхронный метод получает и освобождает внутреннюю блокировку объекта, на который он вызван. Вот почему он может блокироваться. Несинхронизированный метод не пытается получить блокировку (если это явно не указано в коде).
Таким образом, если вам необходимо обеспечить взаимное исключение для M2, вы должны синхронизировать его независимо от того, синхронизированы ли его вызывающие абоненты (например, M1) или нет.
Ответ 3
Замок не принадлежит нити. Блокировка фактически принадлежит объекту (или классу в случае блокировки уровня класса), и поток получает блокировку объекта (или класса в случае блокировки уровня класса) в синхронном контексте. Теперь в java нет распространения блокировки, как описано выше. Вот небольшая демонстрация:
открытый класс TestThread {
/**
* @param args
* @throws InterruptedException
*/
public static void main(String[] args) throws InterruptedException {
// TODO Auto-generated method stub
ThreadCreator1 threadCreator1 = new ThreadCreator1();
ThreadCreator2 threadCreator2 = new ThreadCreator2();
Thread t1 = new Thread(threadCreator1,"Thread 1");
Thread t3 = new Thread(threadCreator1,"Thread 3");
Thread t2 = new Thread(threadCreator2,"Thread 2");
t1.start();
Thread.sleep(2000);
t3.start();
}
}
public class ThreadCreator1 реализует Runnable {
private static final Task task= new Task();
private static final Task2 task2= new Task2();
@Override
public void run() {
try {
if(Thread.currentThread().getName().equals("Thread 1"))
task.startTask2(task2);
if(Thread.currentThread().getName().equals("Thread 3"))
task2.startTask();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// TODO Auto-generated method stub
/**/
}
}
открытый класс Задача {
public static final Task task = new Task();
public static List<String> dataList = new ArrayList<String>();
ReentrantLock lock = new ReentrantLock();
public void startTask2(Task2 task2) throws InterruptedException
{
try{
lock.lock();
//new Task2().startTask();
task2.startTask();
}
catch(Exception e)
{
}
finally{
lock.unlock();
}
}
}
открытый класс Task2 {
ReentrantLock lock = new ReentrantLock();
public void startTask() throws InterruptedException
{
try{
//lock.lock();
for(int i =0 ;i< 10;i++)
{
System.out.println(" *** Printing i:"+i+" for:"+Thread.currentThread().getName());
Thread.sleep(1000);
}
}
catch(Exception e)
{
}
/*finally
{
lock.unlock();
}*/
}
}
Просто я использовал замок Reentrant. Если приведенный выше код запущен, то между потоком 1 и потоком 3 будет чередоваться, но если часть блокировки класса Task2 раскоментирована, тогда не будет чередования, и поток, который сначала получает блокировку, сначала будет полностью завершен, затем он освободит замок, а затем другой поток может продолжить.
Ответ 4
Блокировка принадлежит потоку, а не методу (или, точнее, его стеку стека). Так получилось, что если у вас есть синхронизированный метод, вам гарантируется, что поток будет владеть блокировкой до начала запуска метода, и впоследствии выпустит его.
Другой поток может вызывать второй несинхронизированный метод. Несинхронизированный метод может быть вызван любым потоком в любое время.