Мне было интересно, не будет ли у меня странного поведения в Java, если я дважды синхронизирую один и тот же объект?
Сценарий следующий
pulbic class SillyClassName {
object moo;
...
public void method1(){
synchronized(moo)
{
....
method2();
....
}
}
public void method2(){
synchronized(moo)
{
doStuff();
}
}
}
Оба метода используют объект и синхронизируются с ним. Остановится ли второй метод при вызове первым из-за того, что он заблокирован?
Я так не думаю, потому что это тот же поток, но я не уверен в каких-либо других странных результатах, которые могут произойти.




В java ключевое слово synchronized в методе в основном синхронизируется с текущим объектом, поэтому фактически он неявно выполняет то, что вы предлагаете выше.
У вас не возникнет проблем с синхронизацией одного объекта в одном методе и последующей синхронизацией того же объекта в другом методе, потому что, как вы говорите, текущий поток уже удерживает блокировку этого объекта.
Без проблем. В вашем примере (как только вы исправите свой код, чтобы избавиться от предупреждений компиляции, которые вы получите;)), синхронизация гарантирует, что блоки в method1 и method2 не будут выполняться одновременно.
Это своего рода точка синхронизации. :)
Обновлено: извините, пропустил часть вашего вопроса, но Фил ответил на него. Подводя итог, можно сказать, что отдельный поток не может заблокировать себя.
Синхронизированные блоки используют блокировки повторно въезжающий, что означает, что если поток уже удерживает блокировку, он может повторно получить ее без проблем. Поэтому ваш код будет работать так, как вы ожидаете.
См. Нижнюю часть страницы Учебник по JavaВнутренние блокировки и синхронизация.
Цитировать по состоянию на 01.01.2015…
Reentrant Synchronization
Recall that a thread cannot acquire a lock owned by another thread. But a thread can acquire a lock that it already owns. Allowing a thread to acquire the same lock more than once enables reentrant synchronization. This describes a situation where synchronized code, directly or indirectly, invokes a method that also contains synchronized code, and both sets of code use the same lock. Without reentrant synchronization, synchronized code would have to take many additional precautions to avoid having a thread cause itself to block.
Нет, второй метод не остановится, если будет вызван первым. Никаких странных результатов не произойдет (кроме небольших накладных расходов на проверку блокировки. Это не имеет большого значения. Начиная с Java 6 и далее, в JVM есть укрупнение блокировки - Технический документ о производительности Java SE 6.)
Например, взгляните на исходный код java.util.Vector. Есть много вызовов других синхронизированных методов изнутри синхронизированных методов.
Кажется, что Java полностью поддерживает вложенные блокировки одного объекта в одном потоке. Это означает, что если поток имеет внешнюю и внутреннюю блокировку объекта, а другой поток пытается заблокировать тот же объект, второй поток будет приостановлен до тех пор, пока блокировка и то и другое не будет снята первым потоком.
Мое тестирование проводилось на Java 6 SE.
Во вложенных синхронизированных блоках только одна блокировка будет получена одним и тем же потоком.
Я думаю, что мы должны использовать блокировку повторного входа для того, что вы пытаетесь сделать. Вот отрывок из http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/locks/ReentrantLock.html.
What do we mean by a reentrant lock? Simply that there is an acquisition count associated with the lock, and if a thread that holds the lock acquires it again, the acquisition count is incremented and the lock then needs to be released twice to truly release the lock. This parallels the semantics of synchronized; if a thread enters a synchronized block protected by a monitor that the thread already owns, the thread will be allowed to proceed, and the lock will not be released when the thread exits the second (or subsequent) synchronized block, but only will be released when it exits the first synchronized block it entered protected by that monitor.
Хотя я не пробовал это делать, я думаю, если вы хотите сделать то, что у вас есть выше, вы должны использовать блокировку повторного входа.
Интересно, что произойдет, если метод 2 не будет вызван из метода 1, и если оба метода 1 и 2 будут вызваны одновременно, например, объектами 1 и 2. Поскольку оба метода блокируют один и тот же объект moo, только один из эти два метода будут выполняться одновременно?