Вопрос с собеседования · Java

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

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

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

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

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

Подробно

Вторая причина важнее первой и часто выпадает из ответа: 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 без строгого обоснования.

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

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

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

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

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

Разбор темы

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

Партнёр платформы

Разбор собеседования с sotto

После собеседования sotto разбирает разговор: оценка, каждый вопрос — хорошо, частично или слабо, чего не хватило в ответе и над чем поработать к следующему разу. Первые 30 минут бесплатно.

Разбор собеседования