Ключевое слово synchronized появилось в Java с момента поддержки многопоточности для гарантии эксклюзивного доступа к блокам кода или методам из разных потоков. Исторически это ответ Java на классические проблемы race condition и data inconsistency, которые возникают при одновременном обращении к разделяемым данным из разных потоков.
Проблема при работе с многопоточностью — обеспечение "атомарности" операций и предотвращение противоречивых изменений состояний объектов. Неправильная работа с synchronized может привести к взаимоблокировкам (deadlock), деградации производительности или даже к отсутствию синхронизации при неверном выборе объекта-монитора.
Решение — использовать ключевое слово synchronized для метода или блока кода, где требуется гарантировать, что только один поток одновременно выполняет этот участок. Нужно тщательно выбирать объект-синхронизатор, избегать длинных критических секций, а для более сложных задач использовать специальные классы из пакета java.util.concurrent.
Пример кода:
public class Counter { private int count = 0; public synchronized void increment() { count++; } public int getCount() { return count; } } // Синхронизация только части кода на отдельном объекте: private final Object lock = new Object(); public void complexIncrement() { synchronized (lock) { // критическая секция count++; } }
Ключевые особенности:
В чем разница между synchronized-методом и synchronized-блоком?
Синхронизированный метод блокирует "монитор" объекта (или класса, если метод static), синхронизированный блок позволяет явно указать объект-монитор, что дает большую гибкость.
Что произойдет, если в одном объекте синхронизировать разные методы?
Если оба метода помечены synchronized (не static), оба используют в качестве монитора сам объект (this). Один поток не сможет зайти ни в один из методов, пока другой в них находится.
Можно ли синхронизировать статические методы и обычные? Как разблокируются они друг относительно друга?
Статические методы используют монитор самого класса (объект Class), обычные — объект экземпляра. Следовательно, статический synchronized-метод и обычный synchronized-метод не блокируют друг друга.
Разработчик синхронизирует методы разных объектов, но использует везде в качестве монитора один и тот же String. В итоге появляется замедление и "случайные" взаимоблокировки из-за переиспользования строк из пула.
Плюсы:
Минусы:
Синхронизация по приватному final-объекту, который создается только внутри класса (private final Object lock), и критические секции минимальны по времени.
Плюсы:
Минусы: