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

Почему вызов wait() принято помещать в цикл while, а не в if?

MiddleМногопоточность
Коротко

Пробуждение не гарантирует, что условие выполнено: возможны ложные пробуждения (spurious wakeup), а между notify и захватом монитора другой поток мог снова изменить состояние. Поэтому условие перепроверяют в while.

  • notify лишь переводит поток в очередь на монитор
  • notifyAll безопаснее notify, если ждут по разным условиям
  • То же правило для Condition.await

А ещё В новом коде — BlockingQueue и другие готовые примитивы вместо wait/notify

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

Подробно

Вторая причина важнее первой и часто выпадает из ответа: notify лишь переводит поток в очередь на монитор, а захватить его он сможет только после освобождения — за это время другой поток вполне может войти и снова нарушить условие. Поэтому проснувшийся обязан перепроверить состояние, а значит нужен цикл. Полезно тут же назвать связанные факты: wait освобождает монитор, а sleep — нет; вызывать wait и notify можно только владея монитором, иначе IllegalMonitorStateException; notifyAll безопаснее notify, потому что notify может разбудить не того ждущего и привести к зависанию. В современном коде вместо этой пары обычно берут Condition или готовые примитивы из java.util.concurrent.

Пример

synchronized (lock) {
    while (queue.isEmpty()) {
        lock.wait();
    }
    return queue.poll();
}

Что хотят услышать

  • Обе причины: ложные пробуждения и перехват состояния.
  • Готовые примитивы как замена.

Частые ошибки

  • Использовать if вместо while.
  • Предпочитать notify вместо notifyAll без строгого обоснования.

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

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

Показать варианты и ответ
  • ✓Поток может проснуться без notify (spurious wakeup), а также условие могло измениться другим потоком, пока пробуждённый ждал возврата монитора
  • ✗Потому что wait() нужно вызывать несколько раз подряд для надёжности
  • ✗Потому что if не компилируется внутри synchronized-блока
  • ✗Чтобы уменьшить время удержания монитора

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

  • Чем wait отличается от sleep по владению монитором?
  • Почему notifyAll обычно безопаснее notify?

Разбор темы

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

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

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

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

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