Ответ
ReentrantLock — это реализация интерфейса Lock из пакета java.util.concurrent.locks, предоставляющая механизм взаимного исключения (mutex) с расширенными возможностями по сравнению с ключевым словом synchronized.
Основные преимущества перед synchronized:
- Гибкость получения блокировки: Возможность попытаться получить lock без блокировки (
tryLock()), с таймаутом или прерываемым ожиданием (lockInterruptibly()). - Честность (Fairness): Можно создать "честную" блокировку (конструктор с
true), которая гарантирует предоставление lock потоку, ждущему дольше всех (FIFO). Уsynchronizedнет такой гарантии. - Раздельные условия ожидания: Возможность создать несколько объектов
Conditionдля одного lock, что позволяет разным потокам ожидать разных событий.
Повторный вход (Reentrancy): Как и synchronized, ReentrantLock является реентерабельным: поток, уже владеющий lock, может захватить его снова, не блокируясь сам себя.
Базовый шаблон использования:
ReentrantLock lock = new ReentrantLock();
// ...
lock.lock(); // Блокирующее получение блокировки
try {
// Критическая секция
sharedResource.modify();
} finally {
lock.unlock(); // ВСЕГДА освобождайте lock в finally-блоке!
}
Пример с tryLock() и таймаутом:
if (lock.tryLock(1, TimeUnit.SECONDS)) {
try {
// Критическая секция
} finally {
lock.unlock();
}
} else {
// Не удалось получить lock за указанное время
System.out.println("Could not acquire the lock");
}
Использование Condition:
ReentrantLock lock = new ReentrantLock();
Condition condition = lock.newCondition();
// Поток A: ожидание
lock.lock();
try {
while (!someCondition) {
condition.await(); // Освобождает lock и ждёт сигнала
}
// Действие при выполнении условия
} finally { lock.unlock(); }
// Поток B: сигнализация
lock.lock();
try {
someCondition = true;
condition.signalAll(); // Пробуждает все ожидающие потоки
} finally { lock.unlock(); }
Когда выбирать ReentrantLock:
- Требуется таймаут или прерываемое ожидание блокировки.
- Нужна честность (fair ordering) для предотвращения голодания потоков.
- Требуются сложные схемы синхронизации с использованием нескольких условий (
Condition). - Необходимо проверить, свободна ли блокировка (
tryLock()без блокировки).
Когда достаточно synchronized:
- В большинстве стандартных случаев простой синхронизации.
- Когда важна простота кода и меньшая вероятность ошибок (например, забытый
unlock).