Подтвердить что ты не робот

Если синхронизированный метод вызывает другой несинхронизированный метод, существует ли блокировка несинхронизированного метода

В Java, если синхронный метод содержит вызов несинхронизированного, может ли другой метод по-прежнему одновременно обращаться к несинхронизированному методу? В основном, что я спрашиваю, все в синхронизированном методе имеет блокировку (включая вызовы для других синхронизированных методов)? Большое спасибо

4b9b3361

Ответ 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

Блокировка принадлежит потоку, а не методу (или, точнее, его стеку стека). Так получилось, что если у вас есть синхронизированный метод, вам гарантируется, что поток будет владеть блокировкой до начала запуска метода, и впоследствии выпустит его.

Другой поток может вызывать второй несинхронизированный метод. Несинхронизированный метод может быть вызван любым потоком в любое время.