0

Почему методы wait() и notify() объявлены в классе Object в Java?

26

Почему методы wait() и notify() объявлены в классе Object, а не в классе Thread?

5 ответ(ов)

0

Причина заключается в том, что вы ожидаете на конкретном объекте (или, более точно, его мониторе) для использования данной функциональности.

Я думаю, вы могли бы ошибаться в понимании того, как работают эти методы. Они не просто работают на уровне потоков, то есть это не случай простого вызова wait(), после которого вы будете пробуждены следующим вызовом notify(). Вместо этого вы всегда вызываете wait() на конкретном объекте и только вызовы notify на этом объекте пробуждают вас.

Это удобно, потому что, в противном случае, примитивы параллелизма не могли бы масштабироваться. Это было бы эквивалентно наличию глобальных пространств имен, поскольку любые вызовы notify() в любой части вашей программы могли бы нарушить работу любого конкурентного кода, так как они пробуждали бы любые потоки, блокирующиеся на вызове wait(). Вот почему вы вызываете их на конкретном объекте; это задает контекст для работы пары wait-notify, так что когда вы вызываете myBlockingObject.notify() на приватном объекте, вы можете быть уверены, что только потоки, которые вызывали методы ожидания в вашем классе, будут пробуждены. Какой-то поток Spring, который может ожидать на другом объекте, не будет пробужден этим вызовом и наоборот.

Правка: Или, чтобы рассмотреть это с другой стороны – я предполагаю, что из вашего вопроса вы думали, что сможете получить доступ к ожидающему потоку и вызвать notify() на этом Потоке, чтобы его пробудить. Причина, по которой это не делается, заключается в том, что вам придется самостоятельно заниматься множеством дополнительных задач. Поток, который собирается ожидать, должен будет опубликовать ссылку на себя где-то, чтобы другие потоки могли ее видеть; это должно быть правильно синхронизировано для обеспечения согласованности и видимости. А когда вы хотите разбудить поток, вам нужно будет получить доступ к этой ссылке, разбудить ее и удалить оттуда, откуда вы ее получили. Это потребует гораздо больше ручной работы и увеличивает вероятность ошибок (особенно в среде с параллельными потоками) по сравнению с простыми вызовами myObj.wait() в спящем потоке и myObj.notify() в потоке-разбудителе.

0

Наиболее простая и очевидная причина заключается в том, что любая сущность (не только поток) может быть монитором для другого потока. Методы wait и notify вызываются на мониторе. Рабочий поток взаимодействует с монитором. Поэтому методы wait и notify находятся в классе Object, а не в классе Thread.

0

Механизм синхронизации включает в себя концепцию — монитор объекта. Когда вызывается метод wait(), запрашивается монитор, и дальнейшее выполнение приостанавливается до тех пор, пока монитор не будет захвачен или не произойдет исключение InterruptedException. Когда вызывается метод notify(), монитор освобождается.

Рассмотрим сценарий, в котором методы wait() и notify() находились бы в классе Thread вместо класса Object. Предположим, в какой-то момент кода вызывается currentThread.wait(), после чего происходит доступ к объекту anObject.

//.........
currentThread.wait();
anObject.setValue(1);
//.........

Когда вызывается currentThread.wait(), запрашивается монитор currentThread, и дальнейшее выполнение останавливается до тех пор, пока монитор не будет захвачен или не произойдет InterruptedException. Теперь, находясь в состоянии ожидания, если из другого потока будет вызван метод foo() другого объекта anotherObject, находящегося в currentThread, выполнение будет заблокировано, даже если вызываемый метод foo() не обращается к anObject. Если бы первый метод wait() был вызван на anObject, а не на самом потоке, то другие вызовы методов (не обращающиеся к anObject) на объектах, находящихся в том же потоке, не заблокировались бы.

Таким образом, вызов методов wait() и notify() на классе Object (или его подклассах) обеспечивает более высокую степень конкуренции, и именно поэтому эти методы находятся в классе Object, а не в классе Thread.

0

Некоторые другие ответы используют слово "монитор", но никто не объясняет, что оно означает.

Термин "монитор" был введён ещё в 1970-х годах и обозначал объект, который имел собственную внутреннюю блокировку и связанный с ней механизм ожидания/уведомления. Подробности можно найти здесь.

Двадцать лет спустя был краткий момент, когда настольные многопроцессорные компьютеры только появились на рынке, и было модно считать, что правильным подходом к проектированию программного обеспечения для них будет создание объектно-ориентированных программ, в которых каждый объект является монитором.

Оказалось, что это не было столь полезной идеей, но именно в этот краткий момент и была изобретена языковая среда Java.

0

Проще говоря:

Для того чтобы вызвать методы wait() или notify(), необходимо владеть монитором объекта. Это означает, что вызовы wait() или notify() должны находиться внутри синхронизированного блока.

synchronized(monitorObj) {
    monitorObj.wait(); // или даже notify()
}

Вот почему эти методы являются частью класса Object.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь