Какие преимущества и недостатки у ключевого слова `synchronized` в Java?

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

Ответ

Преимущества:

  1. Простота использования: Встроенная в язык конструкция. Для базовой синхронизации достаточно добавить ключевое слово к методу или блоку.
  2. Автоматическое управление блокировкой: JVM гарантирует захват и освобождение монитора, что предотвращает утечку блокировок.
  3. Гарантия видимости изменений (happens-before): Запись в память, выполненная одним потоком в synchronized-блоке, гарантированно видна другому потоку, который входит в synchronized-блок для того же объекта-монитора.

Недостатки:

  1. Грубая блокировка: Блокирует весь объект (для методов экземпляра) или весь класс (для статических методов), даже если конфликтующий доступ происходит только к части данных.
  2. Отсутствие расширенного функционала: Невозможно попытаться захватить блокировку (tryLock), задать время ожидания или создать условия (Condition) для более сложной координации потоков.
  3. Риск взаимоблокировки (deadlock): При неправильном порядке захвата нескольких блокировок.
  4. Производительность: В высококонкурентных сценариях может стать узким местом из-за contention (состязания потоков за монитор).

Пример и альтернативы:

// Простой пример с synchronized
public class Counter {
    private int count = 0;

    public synchronized void increment() {
        count++; // Операция атомарна и потокобезопасна
    }
}

// Альтернативы для разных случаев:
// 1. java.util.concurrent.atomic.AtomicInteger - для одиночных переменных
// 2. java.util.concurrent.locks.ReentrantLock - для гибкой блокировки с tryLock, таймаутами
// 3. java.util.concurrent.locks.StampedLock - оптимистичные блокировки для read-heavy сценариев
// 4. Неблокирующие алгоритмы (CAS-операции)