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

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

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

Сценарий выглядит следующим образом

pulbic class SillyClassName {

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

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

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

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

4b9b3361

Ответ 1

реентерабельные

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

Смотрите нижнюю часть Учебник по Java Внутренние блокировки и синхронизация.

Процитировать по состоянию на 2015-01...

Реентеративная синхронизация

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

Ответ 2

Я думаю, что мы должны использовать блокировку реентера для того, что вы пытаетесь сделать. Вот фрагмент из http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/locks/ReentrantLock.html.

Что мы понимаем под повторной блокировкой? Просто, что есть счет сбора, связанный с блокировкой, и если поток, который удерживает блокировку, снова получает его, счет сбора увеличивается и блокировка затем должна быть выпущена дважды, чтобы действительно освободить блокировку. Это параллельна семантике синхронизации; если поток входит в синхронизированный блок, защищенный монитором, который уже принадлежит нити, поток будет разрешен для продолжения, и блокировка не будет выпущена, когда поток выйдет из второго (или последующего) синхронизированного блока, но только будет выпущен когда он выходит из первого синхронизированного блока, который он ввел, защищенный этим монитором.

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

Ответ 3

Нет проблем. В вашем примере (как только вы исправите свой код, чтобы избавиться от предупреждений компиляции, которые вы получите;)), синхронизация гарантирует, что блоки в методах method1 и method2 не будут выполняться одновременно.

Такая точка синхронизации.:)


Изменить: Извините, пропущенные части вашего вопроса, но Филл ответил. Подводя итог, один поток не может блокировать себя.

Ответ 4

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

Мое тестирование было выполнено под Java 6 SE.

Ответ 5

В java ключевое слово synchronized для метода в основном синхронизируется с текущим объектом, поэтому в действительности оно делает то, что вы предлагаете выше, неявно.

У вас не возникнут проблемы с синхронизацией одного объекта в одном методе, а затем синхронизация на одном и том же объекте в другом методе, потому что, как вы говорите, текущий поток уже содержит блокировку этого объекта.

Ответ 6

Нет, второй метод не остановится, если вы вызовете его первым. Никаких нечетных результатов (за исключением небольшого накладного расхода для проверки блокировки.Это не имеет большого значения. Java 6 и далее, у вас есть укрупнение в JVM - http://java.sun.com/performance/reference/whitepapers/6_performance.html)

Например, посмотрите исходный код java.util.Vector. Существует множество вызовов других синхронизированных методов из синхронных методов.