Синхронизация дважды на одном и том же объекте?

Мне было интересно, не будет ли у меня странного поведения в Java, если я дважды синхронизирую один и тот же объект?

Сценарий следующий

pulbic class SillyClassName {

    object moo;
    ...
    public void method1(){
        synchronized(moo)
        {
            ....
            method2();
            ....
        }
    }

    public void method2(){
        synchronized(moo)
        {
            doStuff();
        }
    }
}

Оба метода используют объект и синхронизируются с ним. Остановится ли второй метод при вызове первым из-за того, что он заблокирован?

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

Интересно, что произойдет, если метод 2 не будет вызван из метода 1, и если оба метода 1 и 2 будут вызваны одновременно, например, объектами 1 и 2. Поскольку оба метода блокируют один и тот же объект moo, только один из эти два метода будут выполняться одновременно?

user3366706 17.10.2018 23:28
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
54
1
14 208
6
Перейти к ответу Данный вопрос помечен как решенный

Ответы 6

В 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.

Во вложенных синхронизированных блоках только одна блокировка будет получена одним и тем же потоком.

Akash5288 26.06.2014 22:02

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

Хотя я не пробовал это делать, я думаю, если вы хотите сделать то, что у вас есть выше, вы должны использовать блокировку повторного входа.

Другие вопросы по теме