2015-03-19 9 views
1

Часть 1:вызов Синхронное внутри другого Синхронное

Предположим, следующий фрагмент кода

void method1(){ 

    synchronized (lockObject){ 
     method2(); 
     System.out.println("line4"); 
    } 

} 

void method2(){ 
    System.out.println("line1"); 

    synchronized (lockObject){ 
     System.out.println("line2"); 
    } 

    System.out.println("line3"); 
} 

Это тупиковый? Это безопасный код? Будет ли выход всегда:

line1 
line2 
line3 
line4 

Часть 2:

Что делать, если method2() выполняется в другом потоке? Будет ли выход отличаться? Как это:

void method1(){ 

    synchronized (lockObject){ 
     method2(); 
     System.out.println("line4"); 
    } 

} 

void method2(){ 
     newThread= new Thread(new Runnable() { 
      @Override 
      public void run() {  
       System.out.println("line1"); 
       synchronized (lockObject){ 
        System.out.println("line2"); 
       } 
       System.out.println("line3"); 
      } 
     }).start(); 
} 

Я предполагаю, что выход второго кода может быть:

line4 
line1 
line2 
line3 

Правильно ли это?

+1

попробуйте его и посмотрите. – MadConan

+5

Я пробовал и наблюдал некоторые результаты ... Но информатика - это не наука, основанная на экспериментах! Если вы проводите тест 1000 раз и получаете тот же результат, вы не можете сказать, что результат действителен, если вы не знаете, что делает основной код. – Kasra

+0

@ Kasra вы на 100% прав, тестирование ничего не доказывает с многопоточными проблемами, так как результат будет зависеть от порядка выполнения, и вам может повезти. – Zielu

ответ

6

Да, вы можете синхронизировать несколько раз на одном объекте без взаимоблокировки, он работает как блокировка реентера.

Что касается выхода. Первый - это простой последовательный вывод, и синхронизация на нем не влияет. Второй будет генерировать ожидаемый результат, так как другому потоку придется ждать, пока первый из них выйдет из файла lockObject.

EDIT, порядок строк1 и line4 не определен, так как синхронизации нет. Строки 2 и строка 3 всегда после строки4, хотя, поскольку второй поток не может начать печать строки1 до тех пор, пока первый не покинет блок синхронизации method1.

2

Внутренние замки являются реентерабельными. Нить может приобрести один, даже если он уже владеет этим.

От the Oracle tutorial:

Напомним, что поток не может получить блокировку, принадлежащую другому потоку. Но нить может приобрести блокировку, которой она уже владеет. Разрешить потоку получать один и тот же замок более одного раза, обеспечивает повторную синхронизацию. Это описывает ситуацию, когда синхронизированный код, прямо или косвенно, вызывает метод, который также содержит синхронизированный код, и оба набора кода используют одну и ту же блокировку. Без повторной синхронизации синхронизированный код должен принять много дополнительных мер предосторожности, чтобы избежать блокировки потока.

Для вашего второго примера, новый поток, который вы запускаете, должен будет ждать, пока блокировка не будет освобождена вызовом метода1. Вероятно, вызов метода 1 завершится, освободив блокировку до начала нового потока, потому что запуск нового потока занимает некоторое время, но это не гарантируется. «line1» может быть напечатана до «line4». Для печати строки «line2» вызов метода 1 должен быть завершен первым.

4

Часть 1: Нет, нет тупика, потому что есть только один замок. Тупик происходит, когда несколько замков могут быть приобретены в разных порядках. Выход всегда будет таким же.

Часть 2: Не будет тупика, но порядок, в котором печатаются утверждения, может отличаться. Строки 1 – 3 всегда будут отображаться в правильном порядке относительно друг друга, но оператор «line4» может быть напечатан до строки 1 или строки 2.

Если вы хотите, чтобы линия 4 не встречалась между строками 1 и 2, вам нужно было бы заставить их казаться «атомарной» операцией, перемещая их внутри блока synchronized.

+0

Кажется, мы снова не согласны. Чтобы напечатать строку4 в любом месте, выполнение первого синхронизированного блока должно быть прервано, что синхронизация предназначена для предотвращения в первую очередь – Zielu

+0

@ Zielu Так я вижу это также ... – motoku

+0

Я думаю, что строка4 может быть напечатана в любом месте, поскольку блокировка в методе2 применяется только к строке2. Другие строки (line1 и line3) находятся за пределами синхронизированного блока. – Kasra

Смежные вопросы