Если синхронизированный метод вызывает другой несинхронизированный метод, существует ли блокировка несинхронизированного метода - PullRequest
35 голосов
/ 02 марта 2012

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

Ответы [ 4 ]

56 голосов
/ 02 марта 2012

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

Да и нет.

Если вы находитесь в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 методами в одном и том же экземпляре, один будет блокироваться, пока другой не выйдет из метода.

3 голосов
/ 02 марта 2012

Если поток A вызывает синхронизированный метод M1, который, в свою очередь, вызывает несинхронизированный метод M2, тогда поток B может по-прежнему вызывать M2 без блокировки.

Синхронизированный метод получает и снимает внутреннюю блокировку объекта, для которого он вызывается.Вот почему это может заблокировать.Несинхронизированный метод не пытается получить какую-либо блокировку (если это не сделано явно в коде).

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

2 голосов
/ 05 июня 2013

Замок не принадлежит потоку. Блокировка фактически принадлежит объекту (или классу в случае блокировки уровня класса), и поток получает блокировку объекта (или класса в случае блокировки уровня класса) в синхронизированном контексте. Теперь в 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();

}

}

открытый класс 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

    /**/

    }
}

открытый класс Task {

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 не закомментирована, то чередования не будет, и поток, который сначала получит блокировку, завершится полностью первым, затем это освободит замок, и тогда другой поток может продолжить.

0 голосов
/ 02 марта 2012

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

...