Короткий ответ
Оба механизма обеспечивают взаимное исключение и реентерабельны: поток, уже владеющий монитором или замком, может захватить его повторно. synchronized — встроенная конструкция языка: монитор захватывается при входе в метод или блок и автоматически освобождается при выходе, даже при исключении. ReentrantLock из java.util.concurrent.locks требует явного lock() и освобождения в finally, но даёт больше контроля.
Как это работает подробнее
Возможности synchronized ограничены: нельзя прервать поток, ожидающий блокировку, нельзя установить таймаут ожидания, нет честной (fair) очереди, а захват возможен только в пределах одного метода или блока.
ReentrantLock предоставляет tryLock() (захват без блокировки или с таймаутом), lockInterruptibly() (прерываемое ожидание), честные замки и несколько объектов Condition для тонкого управления ожиданием.
- Именно
tryLockс таймаутом позволяет писать код, устойчивый к deadlock: не получилось захватить блокировку — поток освобождает уже захваченные ресурсы и повторяет попытку.
Пример кода
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class ReentrantLockDemo {
private final Lock lock = new ReentrantLock();
void doWork() {
lock.lock();
try {
// критическая секция
} finally {
lock.unlock(); // обязательно в finally
}
}
}Что использовать на практике
- По умолчанию используй
synchronized: он проще, короче и исключает ошибку «забыл освободить». - Бери
ReentrantLock, когда нужны таймауты ожидания, прерывание ожидающего потока, честная очередность или несколькоCondition. - Всегда освобождай
ReentrantLockвfinally.
Подводные камни
- Забытый
unlock()— главный риск ReentrantLock: после исключения блокировка останется захваченной; synchronized такого не допускает. - Не включай fair-режим без нужды: честная очередность снижает производительность.
- С Java 6 базовая производительность механизмов сопоставима — не выбирай ReentrantLock «ради скорости».
Как отвечать на собеседовании
- Скажи, что общего: взаимное исключение и реентерабельность → покажи автоматическое освобождение у synchronized → перечисли, чего он не умеет: таймаут, прерывание, честность → покажи код ReentrantLock с finally → правило выбора: по умолчанию synchronized, Lock — под конкретные задачи.