Ответ
java.util.concurrent.locks.Lock — это интерфейс для более гибкой и расширенной синхронизации потоков по сравнению с synchronized. Основная реализация — ReentrantLock.
Базовый шаблон использования:
Всегда вызывайте unlock() в блоке finally, чтобы гарантировать освобождение блокировки даже при возникновении исключения.
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
Lock lock = new ReentrantLock();
lock.lock(); // Захват блокировки
try {
// Критическая секция (доступ к общему ресурсу)
sharedResource.modify();
} finally {
lock.unlock(); // Гарантированное освобождение
}
Ключевые возможности Lock (преимущества перед synchronized):
-
Попытка захвата с таймаутом (
tryLock):if (lock.tryLock(1, TimeUnit.SECONDS)) { // Пытается захватить 1 секунду try { /* работа с ресурсом */ } finally { lock.unlock(); } } else { // Действие, если блокировка не получена } -
Прерываемое ожидание (
lockInterruptibly):lock.lockInterruptibly(); // Поток может быть прерван во время ожидания try { /* ... */ } finally { lock.unlock(); } -
Честность (fairness):
Lock fairLock = new ReentrantLock(true); // Очередь FIFO для ожидающих потоков -
Условные переменные (
Condition): Позволяют организовать точечное ожидание/сигнализацию.Condition condition = lock.newCondition(); // В потоке 1: lock.lock(); try { while (!conditionMet) { condition.await(); // Освобождает lock и ждёт } } finally { lock.unlock(); } // В потоке 2: lock.lock(); try { conditionMet = true; condition.signal(); // Будит один ожидающий поток } finally { lock.unlock(); }
Когда использовать Lock? В сложных сценариях, где требуется контроль над процессом блокировки: таймауты, прерывания, чередование блокировок или использование нескольких условий ожидания.