В чём преимущество интерфейса Lock над synchronized в Java?

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

Ответ

Интерфейс java.util.concurrent.locks.Lock (и его реализация ReentrantLock) предоставляет более гибкий и расширенный контроль над синхронизацией по сравнению с ключевым словом synchronized.

Основные преимущества Lock:

  1. Возможность попытки захвата блокировки:

    Lock lock = new ReentrantLock();
    if (lock.tryLock(2, TimeUnit.SECONDS)) { // Ждём не более 2 секунд
        try {
            // Критическая секция
        } finally {
            lock.unlock();
        }
    } else {
        // Действие, если блокировка не получена
    }
  2. Прерываемое ожидание: Метод lockInterruptibly() позволяет прервать поток, ожидающий блокировку.

  3. Честность (Fairness): ReentrantLock можно создать с политикой честности, что уменьшает вероятность голодания потоков.

  4. Разделение на чтение/запись: ReentrantReadWriteLock позволяет множеству потоков читать данные одновременно, но блокирует их на время записи, что повышает производительность.

Стандартный шаблон использования:

Lock lock = new ReentrantLock();
// ...
lock.lock(); // Всегда перед try
try {
    // Критическая секция
} finally {
    lock.unlock(); // Гарантированное освобождение в finally
}

Когда использовать synchronized:

  • В простых случаях, когда достаточно базовой синхронизации.
  • Когда нужна встроенная поддержка мониторов (методы wait(), notify()).

Когда использовать Lock:

  • Когда нужны расширенные возможности (таймауты, прерывания, честность).
  • Для реализации read-write блокировок.
  • Когда логика получения/освобождения блокировки не укладывается в блоковый scope synchronized.