Какие основные типы блокировок используются в многопоточности Java?

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

Ответ

В Java многопоточность использует несколько типов блокировок и механизмов синхронизации:

1. Неявные (Intrinsic) блокировки через synchronized

  • Используется ключевое слово synchronized для методов или блоков кода.
  • Простой в использовании, но ограниченный функционал (нет таймаутов, чередования блокировок).
    synchronized (lockObject) {
    // Критическая секция
    }

2. Явные (Explicit) блокировки из java.util.concurrent.locks

  • ReentrantLock: Повторно входимая блокировка с расширенными возможностями (честная/нечестная политика, таймауты, прерываемое ожидание).
    Lock lock = new ReentrantLock();
    lock.lock();
    try {
    // Критическая секция
    } finally {
    lock.unlock(); // Важно освобождать в finally
    }
  • ReentrantReadWriteLock: Разделяет блокировки на чтение (множественные) и запись (эксклюзивную).
  • StampedLock: Высокопроизводительная блокировка с поддержкой режимов: пессимистичного и оптимистичного чтения, а также записи.

3. Атомарные операции (Lock-free)

  • Классы java.util.concurrent.atomic (например, AtomicInteger).
  • Основаны на операции Compare-And-Swap (CAS), что часто эффективнее блокировок для простых обновлений.

4. Координационные примитивы (Higher-level synchronization)

  • Semaphore: Ограничивает количество потоков, одновременно входящих в секцию.
  • CountDownLatch: Позволяет потоку ждать завершения операций в других потоках.
  • CyclicBarrier: Заставляет группу потоков ждать друг друга в определенной точке.

Выбор зависит от сценария: synchronized для простых случаев, явные блокировки для гибкости, атомарные классы для производительности, координационные примитивы для сложного взаимодействия потоков.