Java: notify () vs. notifyAll () снова и снова

Если один Googles «разницу между notifyAll() notify() и notifyAll() », тогда появится много объяснений (не считая абзацев javadoc). Все это сводится к тому, что количество ожидающих streamов пробуждается: одно в notify notify() и все в notifyAll() .

Однако (если я правильно понимаю разницу между этими методами), для дальнейшего наблюдения за монитором всегда выбирается только один stream; в первом случае – тот, который выбран виртуальной машиной, во втором случае – тот, который выбран планировщиком системных streamов. Точные процедуры выбора для обоих из них (в общем случае) не известны программисту.

Какая разница между notify () и notifyAll () ? Я что-то упускаю?

26 Solutions collect form web for “Java: notify () vs. notifyAll () снова и снова”

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

В некоторых случаях все ожидающие streamи могут принимать полезные действия после завершения ожидания. Примером может служить набор streamов, ожидающих завершения определенной задачи; как только задача будет завершена, все ожидающие streamи могут продолжать свою деятельность. В таком случае вы будете использовать notifyAll () для одновременного пробуждения всех ожидающих streamов.

Другой случай, например взаимоисключающая блокировка, только один из ожидающих streamов может сделать что-то полезное после уведомления (в этом случае получить блокировку). В таком случае вы предпочитаете использовать notify () . Правильно реализовано, вы также можете использовать notifyAll () в этой ситуации, но вы без необходимости просыпаете streamи, которые ничего не могут сделать.

Ясно, что notify следах (любом) один stream в наборе ожидания, notifyAll просыпает все streamи в ожидании. Следующее обсуждение должно устранить любые сомнения. notifyAll следует использовать большую часть времени. Если вы не уверены, что использовать, то используйте notifyAll Пожалуйста, см. Объяснение, которое следует.

Читайте очень внимательно и понимайте. Если у вас есть какие-либо вопросы, пришлите мне электронное письмо.

Посмотрите на производителя / потребителя (предположение – class ProducerConsumer с двумя методами). ЭТО БРОКЕН (потому что он использует notify ) – да, это МОЖЕТ работать – даже большую часть времени, но это может также вызвать тупик – мы увидим, почему:

 public synchronized void put(Object o) { while (buf.size()==MAX_SIZE) { wait(); // called if the buffer is full (try/catch removed for brevity) } buf.add(o); notify(); // called in case there are any getters or putters waiting } public synchronized Object get() { // Y: this is where C2 tries to acquire the lock (ie at the beginning of the method) while (buf.size()==0) { wait(); // called if the buffer is empty (try/catch removed for brevity) // X: this is where C1 tries to re-acquire the lock (see below) } Object o = buf.remove(0); notify(); // called if there are any getters or putters waiting return o; } 

В ПЕРВУЮ ОЧЕРЕДЬ,

Зачем нам нужен цикл while, окружающий ожидание?

Нам нужен цикл while, если мы получим следующую ситуацию:

Потребитель 1 (C1) вводит синхронизированный блок, и буфер пуст, поэтому C1 помещается в набор ожидания (через вызов wait ). Потребитель 2 (C2) собирается ввести синхронизированный метод (в точке Y выше), но Producer P1 помещает объект в буфер и впоследствии вызывает notify . Единственный ожидающий stream – C1, поэтому он проснулся и теперь пытается повторно захватить блокировку объекта в точке X (см. Выше).

Теперь C1 и C2 пытаются получить блокировку синхронизации. Один из них (недетерминированно) выбирается и входит в метод, другой блокируется (не ждет – но блокируется, пытаясь получить блокировку метода). Скажем, C2 сначала получает блокировку. C1 все еще блокирует (пытается получить блокировку на X). C2 завершает метод и освобождает блокировку. Теперь C1 получает блокировку. Угадайте, что, повезло, у нас есть цикл while, потому что C1 выполняет проверку цикла (guard) и предотвращается удаление несуществующего элемента из буфера (C2 уже получил его!). Если бы у нас не было while , мы бы получили IndexArrayOutOfBoundsException поскольку C1 пытается удалить первый элемент из буфера!

ТЕПЕРЬ,

Хорошо, теперь зачем нам уведомлять?

В примере с производителем / потребителем выше, похоже, мы можем уйти с notify . Это похоже на то, потому что мы можем доказать, что охранники в цикле ожидания для производителя и потребителя являются взаимоисключающими. То есть, похоже, что мы не можем иметь stream, ожидающий в методе put а также метод get , потому что для того, чтобы быть правдой, тогда должно быть верно следующее:

buf.size() == 0 AND buf.size() == MAX_SIZE (предположим, что MAX_SIZE не равно 0)

ОДНАКО, это не очень хорошо, нам notifyAll использовать notifyAll . Давайте посмотрим, почему …

Предположим, что у нас есть буфер размером 1 (чтобы упростить пример). Следующие шаги приводят нас к взаимоблокировке. Обратите внимание, что ANYTIME stream просчитывается с уведомлением, он может быть недетерминированно выбран JVM – это может быть вызвано любой ожидающий stream. Также обратите внимание, что, когда несколько streamов блокируются при входе в метод (т. Е. Пытаются получить блокировку), порядок получения может быть недетерминированным. Помните также, что stream может быть только одним из методов в любой момент времени – синхронизированные методы позволяют выполнять только один stream (т. Е. Удерживать блокировку) любых (синхронизированных) методов в classе. Если происходит следующая последовательность событий – результаты взаимоблокировки:

ШАГ 1:
– P1 помещает 1 символ в буфер

ШАГ 2:
– P2 пытается put – проверяет цикл ожидания – уже присутствует символ

ШАГ 3:
– P3 try put – проверяет цикл ожидания – уже присутствует символ

ШАГ 4:
– C1 пытается получить 1 char
– C2 пытается получить 1 char – блоки при входе в метод get
– C3 пытается получить 1 char – блоки при входе в метод get

ШАГ 5:
– C1 выполняет метод get – получает char, вызывает notify , метод выхода
notify просыпается P2
– НО, C2 вводит метод до того, как P2 может (P2 должен восстановить блокировку), поэтому P2 блокируется при входе в метод put
– C2 проверяет цикл ожидания, больше символов в буфере, поэтому ждет
– C3 вводит метод после C2, но до P2 проверяет цикл ожидания, больше символов в буфере, поэтому ждет

ШАГ 6:
– СЕЙЧАС: ждут P3, C2 и C3!
– Наконец P2 получает блокировку, помещает символ в буфер, вызывает уведомление, выдает метод

ШАГ 7:
– уведомление P2 пробуждает P3 (помните, что любой stream можно разбудить)
– P3 проверяет условие цикла ожидания, в буфере уже есть символ, поэтому ждет.
– НЕТ БОЛЬШЕ НИТИ, ЧТОБЫ ЗВОНИТЬ УВЕДОМЛЕНИЕ, И ТРЕХ НИТЕЙ ПОСТОЯННО ПОДОЗРЕВАЕТСЯ!

РЕШЕНИЕ: Заменить notify с notify notifyAll в notifyAll производителя / потребителя (см. Выше).

Полезные различия:

  • Используйте notify (), если все ваши ожидающие streamи взаимозаменяемы (порядок, который они просыпают, не имеет значения), или если у вас только один ожидающий stream. Общим примером является пул streamов, используемый для выполнения заданий из очереди – при добавлении задания один из streamов уведомляется о пробуждении, выполняет следующее задание и возвращается в режим сна.

  • Используйте notifyAll () для других случаев, когда streamи ожидания могут иметь разные цели и должны иметь возможность запускать одновременно. Примером может служить операция обслуживания совместно используемого ресурса, где несколько streamов ждут завершения операции перед доступом к ресурсу.

Я думаю, что это зависит от того, как создаются и потребляются ресурсы. Если сразу появляется 5 рабочих объектов, и у вас есть 5 потребительских объектов, имеет смысл разбудить все streamи, используя notifyAll (), чтобы каждый мог обрабатывать 1 рабочий объект.

Если у вас есть только один рабочий объект, какой смысл в пробуждении всех потребительских объектов участвовать в гонке за этот один объект? Первый, кто проверяет доступную работу, получит его, и все остальные streamи будут проверять и находить, что им нечего делать.

Я нашел здесь большое объяснение . Вкратце:

Метод notify () обычно используется для пулов ресурсов , где есть произвольное количество «потребителей» или «рабочих», которые берут ресурсы, но когда ресурс добавляется в пул, только один из ожидающих потребителей или работников может справиться с этим. Метод notifyAll () фактически используется в большинстве других случаев. Строго говоря, требуется уведомить официантов о состоянии, которое может позволить нескольким официантам продолжить работу. Но этого часто бывает трудно понять. Итак, как правило, если у вас нет конкретной логики для использования notify (), то вам, вероятно, следует использовать notifyAll () , потому что часто бывает трудно точно узнать, какие streamи будут ждать на конкретном объекте и почему.

Обратите внимание, что с утилитами параллелизма у вас также есть выбор между signal() и signalAll() поскольку эти методы называются там. Поэтому вопрос остается в силе даже с java.util.concurrent .

Дуг Ли поднимает интересный момент в своей знаменитой книге : если Thread.interrupt() возникают notify() и Thread.interrupt() , уведомление может потеряться. Если это может произойти и имеет серьезные последствия notifyAll() это более безопасный выбор, даже если вы платите цену накладных расходов (большую часть времени пробуждаете слишком много streamов).

От Джошуа Блоха, самого Java Guru в Effective Java 2nd edition:

Msgstr “Пункт 69: Предпочитайте утилиты параллелизма, чтобы ждать и уведомлять”.

Вот пример. Запустить его. Затем измените одно из notifyAll (), чтобы уведомить () и посмотреть, что произойдет.

Класс ProducerConsumerExample

 public class ProducerConsumerExample { private static boolean Even = true; private static boolean Odd = false; public static void main(String[] args) { Dropbox dropbox = new Dropbox(); (new Thread(new Consumer(Even, dropbox))).start(); (new Thread(new Consumer(Odd, dropbox))).start(); (new Thread(new Producer(dropbox))).start(); } } 

Класс Dropbox

 public class Dropbox { private int number; private boolean empty = true; private boolean evenNumber = false; public synchronized int take(final boolean even) { while (empty || evenNumber != even) { try { System.out.format("%s is waiting ... %n", even ? "Even" : "Odd"); wait(); } catch (InterruptedException e) { } } System.out.format("%s took %d.%n", even ? "Even" : "Odd", number); empty = true; notifyAll(); return number; } public synchronized void put(int number) { while (!empty) { try { System.out.println("Producer is waiting ..."); wait(); } catch (InterruptedException e) { } } this.number = number; evenNumber = number % 2 == 0; System.out.format("Producer put %d.%n", number); empty = false; notifyAll(); } } 

Класс потребителя

 import java.util.Random; public class Consumer implements Runnable { private final Dropbox dropbox; private final boolean even; public Consumer(boolean even, Dropbox dropbox) { this.even = even; this.dropbox = dropbox; } public void run() { Random random = new Random(); while (true) { dropbox.take(even); try { Thread.sleep(random.nextInt(100)); } catch (InterruptedException e) { } } } } 

Класс продюсера

 import java.util.Random; public class Producer implements Runnable { private Dropbox dropbox; public Producer(Dropbox dropbox) { this.dropbox = dropbox; } public void run() { Random random = new Random(); while (true) { int number = random.nextInt(10); try { Thread.sleep(random.nextInt(100)); dropbox.put(number); } catch (InterruptedException e) { } } } } 

Краткое содержание:

Всегда предпочитайте notifyAll () over notify (), если у вас нет широкомасштабного параллельного приложения, в котором большое количество streamов выполняет одно и то же.

Объяснение:

notify () […] просыпает один stream. Поскольку notify () не позволяет вам указать пробужденный stream, он полезен только в массивно параллельных приложениях, т. Е. Программах с большим количеством streamов, которые выполняют подобные задачи. В таком приложении вам все равно, какой stream проснулся.

Источник: https://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html

Сравните notify () с notifyAll () в описанной выше ситуации: массивное параллельное приложение, в котором streamи выполняют одно и то же. Если вы вызываете notifyAll () в этом случае, notifyAll () будет вызывать пробуждение (то есть планирование) огромного количества streamов, многие из которых неоправданно (поскольку на самом деле может выполняться только один stream, а именно stream, которому будет предоставлен монитор для вызова объекта wait () , notify () или notifyAll () , что приводит к расходованию вычислительных ресурсов.

Таким образом, если у вас нет приложения, где огромное количество streamов выполняет одно и то же одновременно, предпочитайте notifyAll () over notify () . Зачем? Потому что, поскольку другие пользователи уже ответили на этом форуме, уведомите ()

просыпается один stream, который ждет на мониторе этого объекта. […] Выбор произволен и происходит по усмотрению реализации.

источник: Java SE8 API ( https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#notify– )

Представьте, что у вас есть потребительское приложение производителя, где потребители готовы (т.е. wait () ing) потреблять, производители готовы (т.е. wait () ing), чтобы создать, а очередь предметов (которые должны быть произведены / потреблены) пуста. В этом случае notify () может пробудить только потребителей и никогда не производителей, потому что выбор, который пробуждается, является произвольным . Потребительский цикл производителя не будет иметь никакого прогресса, хотя производители и потребители готовы производить и потреблять соответственно. Вместо этого пользователь проснулся (т. Е. Оставив статус wait () ), не вынимает элемент из очереди, потому что он пуст, и уведомляет () о том, что другой потребитель должен продолжить.

Напротив, notifyAll () пробуждает как производителей, так и потребителей. Выбор, который запланирован, зависит от планировщика. Конечно, в зависимости от реализации планировщика планировщик может также планировать только потребителей (например, если вы назначаете streamи потребителей очень высокого приоритета). Однако предположение заключается в том, что опасность планирования планировщика только для потребителей ниже, чем опасность того, что JVM только пробуждает потребителей, потому что любой разумно реализованный планировщик не принимает произвольных решений. Скорее, большинство реализаций планировщика, по крайней мере, пытаются предотвратить голод.

Я очень удивлен, что никто не упомянул о позорной проблеме «потерянного пробуждения» (google it).

В основном:

  1. если у вас есть несколько streamов, ожидающих в одном и том же состоянии, и,
  2. несколько streamов, которые могут заставить вас перейти из состояния A в состояние B и,
  3. несколько streamов, которые могут заставить вас перейти из состояния B в состояние A (обычно те же streamи, что и в 1.) и,
  4. переход из состояния A в B должен уведомлять streamи в 1.

ТОГДА вы должны использовать notifyAll, если у вас нет доказуемых гарантий того, что потерянные пробуждения невозможны.

Общим примером является параллельная очередь FIFO, где: несколько enqueuers (1. и 3. выше) могут переводить вашу очередь из пустых в непустые множественные очереди (2. выше), могут дождаться, когда условие «очередь не пуста» пуст -> непустое должно уведомить об опасности

Вы можете легко написать чередование операций, в которых, начиная с пустой очереди, взаимодействуют 2 enqueuers и 2 dequeuers, а 1 enqueuer будет спать.

Это проблема, сопоставимая с проблемой взаимоблокировки.

Надеюсь, это уберет некоторые сомнения.

notify () : метод notify () пробуждает один stream, ожидающий блокировки (первый stream, который вызывает wait () на этой блокировке).

notifyAll () : метод notifyAll () пробуждает все streamи, ожидающие блокировки; JVM выбирает один из streamов из списка streamов, ожидающих блокировку, и просыпает эту нить вверх.

В случае одного streamа, ожидающего блокировки, нет существенной разницы между notify () и notifyAll (). Тем не менее, когда есть несколько streamов, ожидающих блокировки, как в notify (), так и notifyAll (), точный stream, пробужденный, находится под управлением JVM, и вы не можете программно управлять просыпанием определенного streamа.

На первый взгляд кажется, что рекомендуется просто вызвать notify (), чтобы разбудить один stream; может показаться излишним разбудить все streamи. Однако проблема с notify () заключается в том, что просверленный stream может быть не подходящим для разбудки (stream может ожидать какое-то другое условие, или условие все еще не выполняется для этого streamа и т. Д.). В этом случае функция notify () может быть потеряна, и никакой другой stream не будет просыпаться, что потенциально приведет к типу тупика (уведомление будет потеряно, а все остальные streamи ждут уведомления – навсегда).

Чтобы избежать этой проблемы , всегда лучше вызывать notifyAll (), когда есть несколько streamов, ожидающих блокировку (или несколько условий, на которых выполняется ожидание). Метод notifyAll () пробуждает все streamи, поэтому он не очень эффективен. однако эта потеря производительности незначительна в реальных приложениях.

Все приведенные выше ответы верны, насколько я могу судить, поэтому я расскажу вам еще кое-что. Для производственного кода вы действительно должны использовать classы в java.util.concurrent. Их очень мало можно сделать для вас, в области параллелизма в Java.

Этот ответ представляет собой графическое переписывание и упрощение отличного ответа xagyg , включая комментарии автора.

Зачем использовать notifyAll, даже если каждый продукт предназначен для одного потребителя?

Рассмотрим производителей и потребителей, упрощенных следующим образом.

Режиссер:

 while (!empty) { wait() // on full } put() notify() 

Потребитель:

 while (empty) { wait() // on empty } take() notify() 

Предположим, что 2 производителя и 2 потребителя используют буфер размером 1. На следующем рисунке показан сценарий, ведущий к тупику , которого можно было бы избежать, если бы все streamи использовали notifyAll .

Каждому уведомлению помечен stream, который проснулся.

тупик из-за уведомления

notifyAll() будет просыпать один stream, пока notifyAll() будет пробуждать все. Насколько я знаю, нет среднего места. Но если вы не знаете, что notifyAll() сделает с вашими streamами, используйте notifyAll() . Работает как шарм каждый раз.

notify() позволяет писать более эффективный код, чем notifyAll() .

Рассмотрим следующий fragment кода, который выполняется из нескольких параллельных streamов:

 synchronized(this) { while(busy) // a loop is necessary here wait(); busy = true; } ... synchronized(this) { busy = false; notifyAll(); } 

Его можно сделать более эффективным, используя notify() :

 synchronized(this) { if(busy) // replaced the loop with a condition which is evaluated only once wait(); busy = true; } ... synchronized(this) { busy = false; notify(); } 

В случае, если у вас есть большое количество streamов, или если условие цикла ожидания является дорогостоящим для оценки, notify() будет значительно быстрее, чем notifyAll() . Например, если у вас 1000 streamов, тогда 999 streamов будут пробуждаться и оцениваться после первого notifyAll() , затем 998, затем 997 и т. Д. Напротив, с решением notify() будет пробужден только один stream.

Используйте notifyAll() когда вам нужно выбрать, какой stream будет выполнять следующую работу:

 synchronized(this) { while(idx != last+1) // wait until it's my turn wait(); } ... synchronized(this) { last = idx; notifyAll(); } 

Наконец, важно понять, что в случае notifyAll() код внутри synchronized блоков, которые были пробуждены, будет выполняться последовательно, а не сразу. Предположим, что в приведенном выше примере есть три streamа, а четвертый stream вызывает notifyAll() . Все три streamа будут пробуждены, но только один запустит выполнение и проверит состояние цикла while. Если условие true , оно снова вызовет wait() , и только тогда второй stream начнет выполнение и проверит его состояние цикла while и т. Д.

Вот более простое объяснение:

Вы правы, что если вы используете notify () или notifyAll (), непосредственный результат состоит в том, что ровно один другой stream получит монитор и начнет выполнение. (Предполагая, что некоторые streamи были фактически заблокированы в wait () для этого объекта, другие несвязанные streamи не впитывают все доступные ядра и т. Д.). Воздействие приходит позже.

Предположим, что на этом объекте ждут streamи A, B и C, а stream A получает монитор. Разница заключается в том, что происходит, когда A выпускает монитор. Если вы использовали notify (), то B и C по-прежнему блокируются в ожидании (): они не ждут на мониторе, они ждут уведомления. Когда A отпускает монитор, B и C все еще будут сидеть там, ожидая оповещения ().

Если вы использовали notifyAll (), то B и C перешли в прошлое из состояния ожидания «Ожидание уведомления» и оба ждут получения монитора. Когда A отпускает монитор, B или C его приобретают (если другие нити не конкурируют за этот монитор) и начните выполнение.

Взято из блога на Эффективной Java:

 The notifyAll method should generally be used in preference to notify. If notify is used, great care must be taken to ensure liveness. 

Итак, я понимаю (из вышеупомянутого блога, комментарий «Yann TM» на принятом ответе и Java- документы ):

  • notify (): JVM пробуждает один из ожидающих streamов на этом объекте. Выбор темы производится произвольно без справедливости. То же самое можно разбудить снова и снова. Поэтому состояние системы меняется, но никакого реального прогресса не происходит. Таким образом, создание живого животного .
  • notifyAll (): JVM пробуждает все streamи, а затем все streamи расследуют блокировку этого объекта. Теперь планировщик CPU выбирает stream, который получает блокировку этого объекта. Этот процесс выбора будет намного лучше, чем выбор JVM. Таким образом, обеспечение жизнеспособности.

Взгляните на код, отправленный @xagyg.

Предположим, что два разных streamа ждут двух разных условий:
Первый stream ожидает buf.size() != MAX_SIZE , а второй stream ожидает buf.size() != 0 .

Предположим, что в какой-то точке buf.size() не равно 0 . JVM вызывает notifyAll() notify() вместо notifyAll() , и первый stream уведомляется (а не второй).

Первый stream проснулся, проверяет buf.size() который может вернуть MAX_SIZE , и возвращается к ожиданию. Второй stream не проснулся, продолжает ждать и не вызывает get() .

notify() просыпает первый stream, который вызывает wait() на одном и том же объекте.

notifyAll() просыпает все streamи, которые вызывают wait() на одном и том же объекте.

Сначала будет выполняться stream с наивысшим приоритетом.

Я хотел бы упомянуть, что объясняется в Java Concurrency in Practice:

Первый вопрос, будь то уведомление или уведомление?

 It will be NotifyAll, and reason is that it will save from signall hijacking. 

Если два streamа A и B ждут в разных услови х предикаты той же очереди условий и уведомлений вызывается, то это до JVM, к которому будет уведомляться JVM streamа.

Теперь, если уведомление предназначалось для streamа A и JVM, уведомляемого streamом B, тогда stream B проснется и увидит, что это уведомление не полезно, поэтому он будет ждать снова. И Thread A никогда не узнает об этом пропущенном сигнале, и кто-то угнал его извещение.

Таким образом, вызов notifyAll решит эту проблему, но опять же будет иметь влияние на производительность, поскольку он будет уведомлять обо всех streamах, и все streamи будут конкурировать за одну и ту же блокировку, и он будет включать контекстный переключатель и, следовательно, нагрузку на CPU. But we should care about performance only if it is behaving correctly, if it’s behavior itself is not correct then performance is of no use.

This problem can be solved with using Condition object of explicit locking Lock, provided in jdk 5, as it provides different wait for each condition predicate. Here it will behave correctly and there will not be performance issue as it will call signal and make sure that only one thread is waiting for that condition

notify will notify only one thread which are in waiting state, while notify all will notify all the threads in the waiting state now all the notified threads and all the blocked threads are eligible for the lock, out of which only one will get the lock and all others (including those who are in waiting state earlier) will be in blocked state.

notify() – Selects a random thread from the wait set of the object and puts it in the BLOCKED state. The rest of the threads in the wait set of the object are still in the WAITING state.

notifyAll() – Moves all the threads from the wait set of the object to BLOCKED state. After you use notifyAll() , there are no threads remaining in the wait set of the shared object because all of them are now in BLOCKED state and not in WAITING state.

BLOCKED – blocked for lock acquisition. WAITING – waiting for notify ( or blocked for join completion ).

There are three states for a thread.

  1. WAIT – The thread is not using any CPU cycle
  2. BLOCKED – The thread is blocked trying to acquire a monitor.It might still be using the CPU cycles
  3. RUNNING – The thread is running.

Now, when a notify() is called, JVM picks one thread and move them to to the BLOCKED state and hence to the RUNNING State as there is no competition for the monitor object.

When a notifyAll() is called, JVM picks all the threads and move all of them to BLOCKED State. All these threads will get the lock of the object on a priority basis.Thread which is able to acquire the monitor first will be able to go to the RUNNING state first and so on.

To summarize the excellent detailed explanations above, and in the simplest way I can think of, this is due to the limitations of the JVM built-in monitor, which 1) is acquired on the entire synchronization unit (block or object) and 2) does not discriminate about the specific condition being waited/notified on/about.

This means that if multiple threads are waiting on different conditions and notify() is used, the selected thread may not be the one which would make progress on the newly fulfilled condition – causing that thread (and other currently still waiting threads which would be able to fulfill the condition, etc..) not to be able to make progress, and eventually starvation or program hangup.

In contrast, notifyAll() enables all waiting threads to eventually re-acquire the lock and check for their respective condition, thereby eventually allowing progress to be made.

So notify() can be used safely only if any waiting thread is guaranteed to allow progress to be made should it be selected, which in general is satisfied when all threads within the same monitor check for only one and the same condition – a fairly rare case in real world applications.

When you call the wait() of the “object”(expecting the object lock is acquired),intern this will release the lock on that object and help’s the other threads to have lock on this “object”, in this scenario there will be more than 1 thread waiting for the “resource/object”(considering the other threads also issued the wait on the same above object and down the way there will be a thread that fill the resource/object and invokes notify/notifyAll).

Here when you issue the notify of the same object(from the same/other side of the process/code),this will release a blocked and waiting single thread (not all the waiting threads — this released thread will be picked by JVM Thread Scheduler and all the lock obtaining process on the object is same as regular).

If you have Only one thread that will be sharing/working on this object , it is ok to use the notify() method alone in your wait-notify implementation.

if you are in situation where more than one thread read’s and writes on resources/object based on your business logic,then you should go for notifyAll()

now i am looking how exactly the jvm is identifying and breaking the waiting thread when we issue notify() on a object …

While there are some solid answers above, I am surprised by the number of confusions and misunderstandings I have read. This probably proves the idea that one should use java.util.concurrent as much as possible instead of trying to write own broken concurrent code. Back to the question: to summarize, the best practice today is to AVOID notify() in ALL situations due to the lost wakeup problem. Anyone who doesn’t understand this should not be allowed to write mission critical concurrency code. If you are worried about the herding problem, one safe way to achieve waking one thread up at a time is to: 1. Build an explicit waiting queue for the waiting threads; 2. Have each of the thread in the queue wait for it’s predecessor; 3. Have each thread call notifyAll() when done. Or you can use Java.util.concurrent.*, which have already implemented this.

Waking up all does not make much significance here. wait notify and notifyall, all these are put after owning the object’s monitor. If a thread is in the waiting stage and notify is called, this thread will take up the lock and no other thread at that point can take up that lock. So concurrent access can not take place at all. As far as i know any call to wait notify and notifyall can be made only after taking the lock on the object. Correct me if i am wrong.

  • Как остановить BackgroundWorker при закрытии формы?
  • Неверная операция поперечного streamа: Control 'textBox1', доступ к которому осуществляется из streamа, отличного от streamа, который был создан на
  • SwingUtilities.invokeLater
  • назначение ссылок атомарно, поэтому почему Interlocked.Exchange (ref Object, Object) необходимо?
  • Параллельность: Atomic и volatile в модели памяти C ++ 11
  • Летучие против блокировки против блокировки
  • Разница между загрузчиком classа контекста streamа и обычным загрузчиком classов
  • Доступ к интерфейсу пользовательского интерфейса (Main) безопасно в WPF
  • Почему setState в реале Async вместо Sync?
  • Как обновить пользовательский интерфейс из другого streamа, запущенного в другом classе
  • Как узнать, закончились ли другие streamи?
  • Interesting Posts

    regex для сопоставления чего-либо, если ему не предшествует что-то другое

    Учитывая целое число, как я могу найти следующую большую мощность из двух, используя бит-twiddling?

    Aptitude vs. apt-get: Какой из рекомендованных (так называемых «правильных») инструментов использовать?

    Проблема с Windows XP Internet

    Сравнение с регистром LINQ to Entities

    Могу ли я установить Windows 10 с локальной учетной записью?

    Как получить дату без времени в Java?

    Почему WPF поддерживает привязку к свойствам объекта, но не полям?

    Почему некоторые размещенные приложения Chrome появляются под chrome: // расширениями?

    Makefiles, как я могу их использовать?

    Цветной профиль для уменьшения экрана

    Почему проверка Windows Update настолько медленная?

    Почему глобальные и статические переменные инициализируются значениями по умолчанию?

    Мой код сигнализирует об ошибке «приложение: не процедура» или «вызов не процедуры»

    Windows для быстрого удаления текста?

    Давайте будем гением компьютера.