Ответ
Ключевое слово synchronized в Java обеспечивает взаимное исключение (mutual exclusion) и видимость изменений между потоками для синхронизированного кода. Оно предотвращает состояние гонки (race condition).
Принцип работы: Каждый объект в Java имеет связанную с ним внутреннюю блокировку (intrinsic lock или monitor lock). Когда поток входит в synchronized блок или метод, он захватывает эту блокировку. Другие потоки, пытающиеся войти в любой synchronized блок, защищенный той же самой блокировкой, будут заблокированы до ее освобождения.
Два способа использования:
-
Синхронизированный метод: Блокировка захватывается на объекте
this(для нестатических методов) или на объекте классаClass(для статических методов).public synchronized void increment() { counter++; // Потокобезопасно } -
Синхронизированный блок: Позволяет указать объект-блокировку явно, что дает большую гибкость и может уменьшить область блокировки.
private final Object lock = new Object(); private int counter; public void increment() { // Только этот блок кода синхронизирован, а не весь метод synchronized(lock) { counter++; } }
Важные аспекты (happens-before):
- Все изменения, сделанные в
synchronizedблоке, гарантированно видны любому другому потоку, который впоследствии войдет в блок, синхронизированный по той же самой блокировке. - Это решает проблемы с кешами процессоров и переупорядочиванием инструкций.
Недостатки и альтернативы:
- Deadlock: Риск взаимной блокировки потоков.
- Производительность: Захват и освобождение блокировок имеют накладные расходы.
- Альтернативы из
java.util.concurrent: Для более сложных сценариев используйтеReentrantLock,Semaphore, атомарные классы (AtomicInteger) или concurrent-коллекции (ConcurrentHashMap).