Как работает ключевое слово synchronized в Java?

«Как работает ключевое слово synchronized в Java?» — вопрос из категории Java Core, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Ключевое слово synchronized в Java обеспечивает взаимное исключение (mutual exclusion) и видимость изменений между потоками для синхронизированного кода. Оно предотвращает состояние гонки (race condition).

Принцип работы: Каждый объект в Java имеет связанную с ним внутреннюю блокировку (intrinsic lock или monitor lock). Когда поток входит в synchronized блок или метод, он захватывает эту блокировку. Другие потоки, пытающиеся войти в любой synchronized блок, защищенный той же самой блокировкой, будут заблокированы до ее освобождения.

Два способа использования:

  1. Синхронизированный метод: Блокировка захватывается на объекте this (для нестатических методов) или на объекте класса Class (для статических методов).

    public synchronized void increment() {
        counter++; // Потокобезопасно
    }
  2. Синхронизированный блок: Позволяет указать объект-блокировку явно, что дает большую гибкость и может уменьшить область блокировки.

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