Многопоточное программирование в Java - стр. 5
Освобождение блокировки происходит, даже если возврат метода был вызван неперехваченным исключением.
Другими словами, каждый объект в Java имеет ассоциированный с ним монитор.
Монитор представляет своего рода инструмент для управления доступа к объекту.
Когда выполнение кода доходит до оператора synchronized, монитор объекта захватывается владельцем, и на это время монопольный доступ к синхронизированному коду имеет только один поток, который является владельцем монитора.
После окончания работы блока кода, монитор объекта освобождается и становится доступным для других потоков.
Когда вызывается статический синхронизированный метод, так как статический метод связан с классом, а не с объектом, в этом случае поток получает блокировку для объекта Class, связанного с классом и представляющего класс в среде выполнения.
Таким образом, доступ к синхронизированным статическим полям класса контролируется блокировкой, отличной от блокировки для любого экземпляра класса. Поэтому статические синхронизированные методы и нестатические синхронизированные методы никогда не заблокируют друг друга.
Конструкторы не могут быть синхронизированы – использование ключевого слова synchronized для конструктора является синтаксической ошибкой.
Синхронизация конструктора не имеет смысла, потому что только поток, который создает объект, имеет доступ к нему во время его создания.
Еще раз, если два нестатических метода класса объявлены как synchronized, то в каждый момент времени из разных потоков на одном объекте может быть вызван только один из них.
Поток, который вызывает метод первым, захватит монитор, и второму потоку придется ждать.
Это верно только для разных потоков.
Один и тот же поток может вызвать синхронизированный метод, внутри него – другой синхронизированный метод на том же экземпляре. И это будет повторная блокировка.
Поскольку этот поток владеет монитором, проблем второй вызов не создаст.
Это верно только для вызовов методов одного экземпляра.
У разных экземпляров разные мониторы, поэтому одновременный вызов нестатических методов проблем не создаст.
Другой способ создания синхронизированного кода – синхронизированные блоки.
В отличие от синхронизированных методов, синхронизированные блоки должны указывать объект, который обеспечивает внутреннюю блокировку.
Когда один поток заходит внутрь блока кода, помеченного словом synchronized, то Java-машина тут же блокирует монитор объекта, который указан в круглых скобках после слова synchronized.
Больше ни один поток не сможет зайти в этот блок, пока наш поток его не покинет.
Как только наш поток выйдет из блока, помеченного synchronized, то монитор тут же автоматически освобождается и будет свободен для захвата другим потоком.
Для нестатических методов, синхронизация метода эквивалентна синхронизации тела метода с объектом this.
Для статических методов, синхронизация метода эквивалентна синхронизации тела метода с объектом Class.
Предположим, что класс имеет два поля экземпляра: c1 и c2, которые никогда не используются вместе.
Все обновления этих полей должны быть синхронизированы, но нет никаких причин препятствовать тому, чтобы обновление c1 чередовалось с обновлением c2, чтобы не создавать ненужную блокировку.
Вместо использования синхронизированных методов или использования блокировки this, мы создаем два объекта исключительно для обеспечения блокировок.