wait, notify, notifyAllЧасто этот вопрос формулируется как задача
Producer-сonsumer. Эту задачу и практические задачи на многопоточность вообще при возможности лучше реализовывать на
высокоуровневых примитивах синхронизации. Другой подход – воспользоваться также низкоуровневой, но
оптимистической блокировкой на
compareAndSet. Но обычно использование notify/wait (пессимистическая блокировка) – условие этого задания, то есть требуется
реализовать уже существую
BlockingQueue.
Эти методы вместе с synchronized – самый низкий уровень пессимистических блокировок в Java, использующийся внутри реализации примитивов синхронизации. Еще с Java 5 в непосредственном использовании этих методов
нет необходимости, но теоретические знания всё еще часто спрашивают на интервью.
Чтобы вызывать эти методы у объекта, необходимо чтобы был захвачен его монитор (т.е. нужно быть внутри synchronized-блока на этом объекте). В противном случае будет выброшено IllegalMonitorStateException. Так что для полного ответа нужно понимать, как работает monitor lock (блок synchronized).
Вызов wait тормозит текущий поток на ожидание на этом объекте и отпускает его монитор. Исполнение продолжится, когда другой поток вызовет notify и отпустит блокировку монитора. Если на объекте ожидают несколько потоков, notify разбудит один случайный, notifyAll - все сразу.
В теории, ожидание wait может быть прервано без вызова notify, по желанию JVM (
spurious wakeup). На практике это бывает
крайне редко, но нужно страховаться и после вызова wait добавлять дополнительную проверку условия завершения ожидания.
Еще два нештатных случая завершения wait – прерывание потока извне и таймаут ожидания. В случае прерывания выбрасывается InterruptedException. Для таймаута нужно указать время ожидания параметрами метода wait. Значение 0 проигнорируется.
Различные проблемы реализации блокировок рассмотрены в
Java Concurrency in Practice 14.1.3, 14.2. Для желающих разобраться, как блокировки работают в кишках JVM, написана
статья на хабре.
#МетодыObject
#Многопоточность