Принципиаьное различие notify() от notifyAll() ?

 
 
 
Сообщения:1
Пытаюсь четко понять разницу в использовании notify() от notifyAll(). Знаю, что notifyAll() нотифицирует все ждущие монитор потоки, в то время как notify() воздействует только на один из них. Но ведь на какой из ждущих потоков подействует вызов notify() заранее неизвестно. Так же как и не известно какой именно поток выйдет из ожидания при notifyAll(). Дак в чем тогда принципиальное, фундаментальное различие этих двух методов, если и в том и в другом случае нет сведений какой из ждущих потоков захватит монитор? Только лишь в том, что первый воздейтсвует на один поток, а второй на все?? Но тогда получается вероятность захвата монитора каким-то определенным потоком равна в обоих случаях. Когда и в каких случаях все-таки необходимо использовать один метод, а в каких другой?
 
 
Сообщения:1582
NPE:
Так же как и не известно какой именно поток выйдет из ожидания при notifyAll().

При notify() один поток, при notifyAll() все потоки.

Make HTTP requests easy. http-master.com
 
 
Сообщения:747
Если через notify мы сигнализируем о двух (или более) типах сообщений, и каждый поток ждет сообщения своего типа, то при простом notify проснуться может не тот поток и нотификация потеряется. Это может случиться даже для простой записи/чтения в буфер. Надежное решение - ReentrantLock с отдельными Cobdition для каждого типа сообщений.
 
 
Сообщения:66
The choice is arbitrary and occurs at the discretion of the implementation. - отрывок из доки к notify().
 
 
Сообщения:2428
NPE:
Так же как и не известно какой именно поток выйдет из ожидания при notifyAll().

Как это не известно? Из состояния ожидания выйдут все потоки ждавшие на мониторе.
 
 
Сообщения:2
Vermut:
NPE:
Так же как и не известно какой именно поток выйдет из ожидания при notifyAll().

Как это не известно? Из состояния ожидания выйдут все потоки ждавшие на мониторе.

wait можно вызвать только из синхронизированного кода. Когда вызывается wait монитор освобождается. При вызову notify из другого потока мы просыпаемся в синхронизированном блоке кода, но с отпущенным монитором. Что должно произойти? Я полагаю, что первым делом должен быть захвачен монитор синхронизированного блока кода. В этом случае notify опять же будет отличаться от notifyAll.
В случае, если после просыпания в wait не будет происходить захват монитора, тогда имеется несоответствие между синхронизированным блоком кода семантическим и фактическим.
 
 
Сообщения:2428
Я наверно написал как-то непонятно, поэтому попробую второй раз ответить.

NPE:
Но ведь на какой из ждущих потоков подействует вызов notify() заранее неизвестно.

Да неизвестно.

NPE:
Так же как и не известно какой именно поток выйдет из ожидания при notifyAll().

Все ждавшие на мониторе потоки выйдут по очереди захватывая монитор, и в этом основное отличие - в первом случае разблочится кто-то один, во втором случае все, даже те кому реально не надо.

NPE:
Когда и в каких случаях все-таки необходимо использовать один метод, а в каких другой?

Я вам открою небольшой секрет - начиная с java 5 ни notify ни notiyAll не стоит никогда использовать в виду появления пакета java.util.concurrent. Если Вы программируете под java 4 и древнее, то вообще до фонаря, модель памяти java 1.4(и ранее) имеет доказанные дефекты, и какой бы вы многопоточный код Вы не пытались на этом говне мамонта писать, он будет содержать баги by design, даже такую примитивную вещь как double-check locking на java версии до 1.5 корректно реализовать невозможно.
Изменен:03 апр 2018 23:11
 
 
Сообщения:2428
popovspb:
При вызову notify из другого потока мы просыпаемся в синхронизированном блоке кода, но с отпущенным монитором.

Спека об этом вообще ничего не говорит, быть удаленным из waiting set не значит быть посталенным немедленно на исполненее:
Quote:
If n is greater than zero and this is a notifyAll action, then all threads are removed from m's wait set, and thus resume.Notice, however, that only one of them at a time will lock the monitor required during the resumption of wait.

Не написанно ничего такого, чтобы препятсвовало эффективной реализации ставить на исполнение поток с уже с захваченным монитором. И следуя зрдравому смыслу, не зависимо от уровня в который протекла блокировка, хоть на уровне JVM, хоть разбухла до уровня OS, в обоих случаях я не вижу особых алгоритмических препятсвий, сначало назначить блокировку к потоку и только потом его ставить на исполнение, вместо того чтобы стахостически будить множество тредов неизветного размера.
Изменен:03 апр 2018 23:34
 
 
Сообщения:747
Vermut:
Я вам открою небольшой секрет - начиная с java 5 ни notify ни notiyAll не стоит никогда использовать в виду появления пакета java.util.concurrent.

Ну это вопрос вкуса. У традиционного методе есть свои преимущества - это простота и надежность. Конструкция synchronized синтаксически обеспечивает парность блокировок и разблокировок. При использовании j.u.c.Lock за этим надо следить отдельно.
 
 
Сообщения:2
Правильно ли я понимаю, что вызывая notify, произвольный вызов wait этого объекта будет отпущен с захватом монитора, в то время как остальные вызовы wait в других потоках будут ждать своей очереди, пока не вызовется еще раз notify или notifyAll?
А при вызове notifyAll вызовы wait во всех потоках завершатся, и произойдет захват монитора произвольным потоком. То есть остальные потоки в синхронизированных блоках кода будут ожидать, пока не освободится монитор, захваченный счасливчиком-потоком. И эти потоки будут поочередно захватывать и освобождать монитор, пока все не выйдут из синхронизированного блока кода и не продолжат свою работу.
То есть практическая разница в том, что при вызове notify один поток проснется, остальные продолжат ожидать, а при notifyAll проснутся все, но продолжат свое выполнение поочередно выполняя синхронизированный блок кода?
 
Модераторы:Нет
Сейчас эту тему просматривают:Нет