Sleep внутри synchronized — лок держится всё это время

Это ловушка, которую легко пропустить в коде на код-ревью или на живом собесе, потому что синтаксически всё выглядит правильно.

Thread.sleep() не освобождает монитор объекта. Если вызов sleep стоит внутри synchronized-блока, поток удерживает лок весь период сна — другие потоки, которым нужен этот же монитор, ждут всё это время, даже если реально не выполняется никакой полезной работы.

Это отличается от wait(), который специально спроектирован освобождать монитор на время ожидания и требует synchronized-контекста именно поэтому — чтобы можно было безопасно проверить условие перед отпусканием лока.

synchronized (lock) { // лок удерживается Thread.sleep(5000); // лок всё еще удерживается }

На собесе спросят: а если внутри synchronized стоит блокирующий вызов сети или БД, а не sleep — та же проблема? Да, ровно та же: любой блокирующий ввод-вывод внутри synchronized держит монитор на всё время ожидания. Отсюда правило — минимизировать критическую секцию, выносить сетевые и I/O вызовы за пределы synchronized, где это возможно.

Sleep и блокирующий I/O внутри synchronized — тихий способ превратить редкую задержку в системную деградацию под нагрузкой.

Тренажёр: 600 вопросов, мок с таймером, план повторов

senior·base — что спрашивают на самом деле


В этом посте были ссылки, но мы их удалили по правилам Сетки