Где должен располагаться вызов unlock() при работе с ReentrantLock?
- Чем ReentrantLock отличается от synchronized?
- Что такое tryLock?
unlock() — в finally, а lock() — перед try: иначе исключение в критической секции оставит замок захваченным навсегда.
- В отличие от synchronized, явный замок не освобождается сам
- Зато умеет tryLock с таймаутом, прерываемое ожидание, справедливость, несколько Condition
А ещё Если lock() внутри try и он упадёт — finally вызовет unlock() у не захваченного замка
Подробно
ReentrantLock — явная блокировка из java.util.concurrent.locks. Монитор synchronized освобождается автоматически при любом выходе из блока, а явный замок нужно освободить вручную. Если между lock() и unlock() вылетит исключение и unlock() не выполнится, замок останется захваченным, и все остальные потоки встанут в ожидание навсегда — внешне это выглядит как зависание без ошибок в логах.
Поэтому шаблон строгий: lock() — непосредственно перед try, unlock() — в finally. Захват ставят вне try: если бы lock() оказался внутри и сам бросил исключение, finally попытался бы освободить незахваченный замок и получил бы IllegalMonitorStateException.
Зачем вообще явный замок, если есть synchronized:
tryLock()иtryLock(timeout)— попытаться захватить, не блокируясь навсегда;lockInterruptibly()— ожидание, которое можно прервать;- справедливый режим — очередь потоков в порядке прихода;
- несколько условий
Conditionвместо одногоwait/notify; ReentrantReadWriteLock— параллельные чтения при редких записях.
Если эти возможности не нужны, synchronized проще и безопаснее.
Пример
private final ReentrantLock lock = new ReentrantLock();
void transfer() {
lock.lock();
try {
// критическая секция
} finally {
lock.unlock();
}
}Что хотят услышать
- unlock в finally и lock перед try, с объяснением почему.
- Чем явный замок отличается от synchronized.
- Возможности: tryLock, прерываемость, Condition.
Частые ошибки
- Помещать захват внутрь try.
- Забывать освобождение при раннем возврате из метода.
Проверьте себя
Один верный вариант. Подумайте, потом откройте ответ.
Показать варианты и ответ
- ✗Сразу после lock(), до основной работы, чтобы не держать замок
- ✓В finally, иначе исключение оставит замок захваченным
- ✗В конце метода, после блока try
- ✗Вызывать его не нужно — блокировка снимается автоматически
Что спросят дальше
- Какие возможности даёт явная блокировка по сравнению с synchronized?
- Зачем нужен захват с таймаутом?
Разбор темы
- Явные блокировки: ReentrantLock, RW и Condition
Когда synchronized мало, ReentrantLock с tryLock/fairness, ReadWriteLock и StampedLock, Condition вместо wait/notify.
Связанные вопросы
Разбор собеседования с sotto
После собеседования sotto разбирает разговор: оценка, каждый вопрос — хорошо, частично или слабо, чего не хватило в ответе и над чем поработать к следующему разу. Первые 30 минут бесплатно.