Получить доступ

Где должен располагаться вызов unlock() при работе с ReentrantLock?

JuniorМногопоточность
Ещё спрашивают так:
  • Чем ReentrantLock отличается от synchronized?
  • Что такое tryLock?
Коротко

unlock() — в finally, а lock() — перед try: иначе исключение в критической секции оставит замок захваченным навсегда.

  • В отличие от synchronized, явный замок не освобождается сам
  • Зато умеет tryLock с таймаутом, прерываемое ожидание, справедливость, несколько Condition

А ещё Если lock() внутри try и он упадёт — finally вызовет unlock() у не захваченного замка

Так подсказку видит пользователь sotto на живом собеседовании — за пару секунд, пока вы думаете вслух.

Подробно

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.
  • Забывать освобождение при раннем возврате из метода.

Проверьте себя

Один верный вариант. Подумайте, потом откройте ответ.

Показать варианты и ответ
  • ✓В блоке finally — иначе исключение внутри критической секции оставит блокировку захваченной навсегда
  • ✗Сразу после lock(), до основной работы
  • ✗В конце метода, после блока try
  • ✗Вызывать его не нужно — блокировка снимается автоматически

Что спросят дальше

  • Какие возможности даёт явная блокировка по сравнению с synchronized?
  • Зачем нужен захват с таймаутом?

Разбор темы

Связанные вопросы

Закрытая бета

Подсказки на собеседовании — в реальном времени

sotto слышит вопрос интервьюера и показывает короткий ответ и план, как в блоке «Коротко». Оставьте контакт — пришлём доступ и промокод.

  • Промокод на 2 часа — сверх пробных 30 минут
  • Программа для Windows — скачать сразу, войти — через Яндекс ID или VK ID
  • Прямая связь с разработчиком: что улучшить — сделаем