Можно ли вызвать метод wait() у объекта вне блока synchronized в Java?

«Можно ли вызвать метод wait() у объекта вне блока synchronized в Java?» — вопрос из категории Java Core, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Нет, вызов wait() вне синхронизированного контекста приведет к IllegalMonitorStateException.

Причина: Перед тем как перейти в состояние ожидания и освободить монитор, поток должен этот монитор захватить. Это фундаментальное требование механизма wait/notify.

Некорректный вызов:

Object monitor = new Object();
monitor.wait(); // IllegalMonitorStateException!

Корректный шаблон использования (шаблон "Guarded Blocks"):

synchronized (monitor) {
    while (!someCondition) { // Всегда используйте цикл, а не if!
        monitor.wait(); // 1. Освобождает монитор 'monitor'
                         // 2. Переходит в состояние WAITING
                         // 3. После пробуждения заново захватывает монитор
    }
    // Выполнение работы, когда условие выполнено
}

Ключевые моменты:

  1. Цикл while: Необходим для защиты от ложных пробуждений (spurious wakeups), которые разрешены спецификацией JVM.
  2. Атомарность: Синхронизация гарантирует, что проверка условия !someCondition и вызов wait() происходят как одна неделимая операция. Без этого другой поток мог бы изменить условие и вызвать notify() в промежутке между проверкой и ожиданием, что привело бы к вечному ожиданию.