Java: notify () vs. notifyAll () di nuovo

Se un googles per “differenza tra notify() e notifyAll() ” allora appariranno molte spiegazioni (lasciando a parte i paragrafi javadoc). Tutto si riduce al numero di thread in attesa che si svegliano: uno in notify() e tutto in notifyAll() .

Tuttavia (se capisco la differenza tra questi metodi a destra), solo un thread è sempre selezionato per un’ulteriore acquisizione del monitor; nel primo caso quello selezionato dalla VM, nel secondo caso quello selezionato dal programmatore di thread di sistema. Le esatte procedure di selezione per entrambi (nel caso generale) non sono note al programmatore.

Qual è la differenza utile tra notify () e notifyAll () allora? Mi sto perdendo qualcosa?

In poche parole, dipende dal motivo per cui i thread sono in attesa di essere notificati. Vuoi dire a uno dei thread in attesa che qualcosa è successo, o vuoi raccontarli tutti allo stesso tempo?

In alcuni casi, tutti i thread in attesa possono agire in modo utile una volta terminata l’attesa. Un esempio potrebbe essere un insieme di thread in attesa che una determinata attività termini; una volta che l’attività è terminata, tutti i thread in attesa possono continuare con la loro attività. In tal caso, si dovrebbe usare notifyAll () per svegliare tutti i thread in attesa allo stesso tempo.

Un altro caso, ad esempio il blocco reciprocamente esclusivo, solo uno dei thread in attesa può fare qualcosa di utile dopo essere stato avvisato (in questo caso acquisire il blocco). In tal caso, preferiresti usare notify () . Se correttamente implementato, potresti usare notifyAll () anche in questa situazione, ma sveglierai inutilmente i thread che non possono comunque fare nulla.

Chiaramente, notify risveglia (qualsiasi) un thread nel set di attesa, notifyAll ritriggers tutti i thread nel set di attesa. La seguente discussione dovrebbe chiarire ogni dubbio. notifyAll dovrebbe essere usato la maggior parte del tempo. Se non si è sicuri di quale usare, utilizzare notifyAll . notifyAll spiegazione che segue.

Leggi molto attentamente e capisci. Vi prego di inviarmi una e-mail se avete domande.

Guarda produttore / consumatore (l’ipotesi è una class ProducerConsumer con due metodi). È ROTTO (perché usa la notify ) – sì, può funzionare – anche la maggior parte del tempo, ma può anche causare deadlock – vedremo perché:

 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; } 

IN PRIMO LUOGO,

Perché abbiamo bisogno di un ciclo temporale che circonda l’attesa?

Abbiamo bisogno di un ciclo temporale nel caso avessimo questa situazione:

Consumer 1 (C1) entra nel blocco sincronizzato e il buffer è vuoto, quindi C1 viene messo nel set di attesa (tramite la chiamata di wait ). Consumer 2 (C2) sta per entrare nel metodo sincronizzato (al punto Y sopra), ma Producer P1 mette un object nel buffer e successivamente chiama notify . L’unico thread in attesa è C1, quindi è stato risvegliato e ora tenta di riacquistare il blocco dell’object al punto X (sopra).

Ora C1 e C2 stanno tentando di acquisire il blocco di sincronizzazione. Uno di essi (non deterministico) viene scelto ed entra nel metodo, l’altro è bloccato (non in attesa – ma bloccato, cercando di acquisire il blocco sul metodo). Diciamo che C2 ottiene prima il blocco. C1 sta ancora bloccando (cercando di acquisire il blocco su X). C2 completa il metodo e rilascia il blocco. Ora, C1 acquisisce il blocco. Indovinate un po ‘, fortunatamente abbiamo un ciclo while , perché, C1 esegue il controllo del ciclo (guardia) e viene impedito di rimuovere un elemento inesistente dal buffer (C2 lo ha già ottenuto!). Se non avessimo avuto un while , avremmo ottenuto un IndexArrayOutOfBoundsException mentre C1 prova a rimuovere il primo elemento dal buffer!

ADESSO,

Ok, ora, perché abbiamo bisogno di notifyAll?

Nell’esempio produttore / consumatore sopra sembra che possiamo farcela con la notify . Sembra così, perché possiamo dimostrare che le guardie sui loop di attesa per produttore e consumatore si escludono a vicenda. Cioè, sembra che non possiamo avere un thread in attesa nel metodo put così come il metodo get , perché, affinché ciò sia vero, allora il seguente dovrebbe essere vero:

buf.size() == 0 AND buf.size() == MAX_SIZE (supponiamo MAX_SIZE non è 0)

TUTTAVIA, questo non è abbastanza buono, abbiamo bisogno di usare notifyAll . Vediamo perché …

Supponiamo di avere un buffer di dimensione 1 (per rendere l’esempio facile da seguire). I seguenti passaggi ci portano al punto morto. Si noti che ANYTIME un thread viene svegliato con notify, può essere selezionato non-deterministicamente dalla JVM – cioè qualsiasi thread in attesa può essere risvegliato. Si noti inoltre che quando più thread stanno bloccando l’accesso a un metodo (cioè cercando di acquisire un blocco), l’ordine di acquisizione può essere non deterministico. Ricorda inoltre che un thread può essere solo in uno dei metodi in qualsiasi momento: i metodi sincronizzati consentono solo l’esecuzione di un solo thread (ovvero il blocco di) qualsiasi metodo (sincronizzato) nella class. Se si verifica la seguente sequenza di eventi: risultati deadlock:

PASSO 1:
– P1 mette 1 carattere nel buffer

PASSO 2:
– P2 tentativi put – controlla il ciclo di attesa – già un char – attende

PASSO 3:
– P3 tentativi put – controlla il ciclo di attesa – già un char – attende

PASSO 4:
– C1 tenta di ottenere 1 carattere
– C2 tenta di ottenere 1 char – block in ingresso per il metodo get
– C3 tenta di ottenere 1 char – block in ingresso per il metodo get

PASSO 5:
– C1 sta eseguendo il metodo get – ottiene il char, chiama notify , termina il metodo
– La notify triggers P2
– BUT, C2 entra nel metodo prima che il P2 possa (P2 deve riacquisire il lock), quindi i blocchi P2 entrano nel metodo put
– C2 controlla il ciclo di attesa, non ci sono più caratteri nel buffer, quindi aspetta
– C3 entra nel metodo dopo C2, ma prima di P2, controlla il ciclo di attesa, non ci sono più caratteri nel buffer, quindi aspetta

PASSAGGIO 6:
– ORA: ci sono P3, C2 e C3 in attesa!
– Finalmente P2 acquisisce il lock, inserisce un char nel buffer, chiama notify, exit method

PASSO 7:
– La notifica di P2 ritriggers P3 (ricorda che qualsiasi thread può essere svegliato)
– P3 controlla la condizione del ciclo di attesa, c’è già un carattere nel buffer, quindi aspetta.
– NESSUN ALTRO FILETTO PER CHIAMARE NOTIFY E TRE FILETTATI PERMANENTEMENTE SOSPESI!

SOLUZIONE: Sostituisci notify con notifyAll nel codice produttore / consumatore (sopra).

Differenze utili:

  • Usa notify () se tutti i tuoi thread in attesa sono intercambiabili (l’ordine in cui si svegliano non ha importanza) o se hai solo un thread in attesa. Un esempio comune è un pool di thread utilizzato per eseguire i lavori da una coda: quando un lavoro viene aggiunto, uno dei thread viene avvisato per svegliarsi, eseguire il lavoro successivo e tornare a dormire.

  • Utilizzare notifyAll () per altri casi in cui i thread in attesa potrebbero avere scopi diversi e dovrebbero essere in grado di essere eseguiti contemporaneamente. Un esempio è un’operazione di manutenzione su una risorsa condivisa, in cui più thread sono in attesa del completamento dell’operazione prima di accedere alla risorsa.

Penso che dipenda da come le risorse vengono prodotte e consumate. Se 5 oggetti di lavoro sono disponibili contemporaneamente e si hanno 5 oggetti di consumo, sarebbe opportuno risvegliare tutti i thread utilizzando notifyAll () in modo che ognuno possa elaborare 1 object di lavoro.

Se hai a disposizione un solo object di lavoro, che senso ha risvegliare tutti gli oggetti di consumo per correre verso quell’unico object? Il primo che verifica il lavoro disponibile lo otterrà e tutti gli altri thread controlleranno e scopriranno che non hanno nulla da fare.

Ho trovato un’ottima spiegazione qui . In breve:

Il metodo notify () viene generalmente utilizzato per i pool di risorse , dove esiste un numero arbitrario di “consumatori” o “lavoratori” che prendono risorse, ma quando una risorsa viene aggiunta al pool, solo uno dei consumatori in attesa o i lavoratori possono occuparsi con esso. Il metodo notifyAll () è effettivamente utilizzato nella maggior parte degli altri casi. Rigorosamente, è necessario notificare ai camerieri una condizione che potrebbe consentire a più camerieri di procedere. Ma questo è spesso difficile da sapere. Quindi, come regola generale, se non si dispone di una logica particolare per l’utilizzo di notify (), è consigliabile utilizzare notifyAll () , poiché è spesso difficile sapere esattamente quali thread saranno in attesa su un particolare object e perché.

Si noti che con le utilità di concorrenza si ha anche la scelta tra signal() e signalAll() poiché questi metodi vengono chiamati lì. Quindi la domanda rimane valida anche con java.util.concurrent .

Doug Lea mostra un punto interessante nel suo famoso libro : se un notify() e Thread.interrupt() verificano contemporaneamente, la notifica potrebbe effettivamente andare persa. Se questo può accadere e ha implicazioni drammatiche, notifyAll() è una scelta più sicura anche se paghi il prezzo del sovraccarico (svegliando troppi thread la maggior parte del tempo).

Da Joshua Bloch, lo stesso Java Guru in Java 2a edizione:

“Articolo 69: Preferire le utilità di concorrenza per attendere e notificare”.

Ecco un esempio. Eseguirlo. Quindi modificare uno dei notifyAll () per notify () e vedere cosa succede.

ProducerConsumerEsempio di class

 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(); } } 

Classe 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(); } } 

Classe di consumo

 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) { } } } } 

Classe di produttori

 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) { } } } } 

Breve riassunto:

Preferisci sempre notifyAll () over notify () a meno che tu non abbia un’applicazione massicciamente parallela in cui un gran numero di thread facciano tutti la stessa cosa.

Spiegazione:

notify () […] ritriggers un singolo thread. Poiché notify () non ti permette di specificare il thread che è stato risvegliato, è utile solo in applicazioni massivamente parallele – cioè programmi con un numero elevato di thread, tutti che svolgono compiti simili. In un’applicazione del genere, non ti interessa quale thread viene svegliato.

fonte: https://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html

Confronta notify () con notifyAll () nella situazione sopra descritta: un’applicazione massicciamente parallela in cui i thread stanno facendo la stessa cosa. Se si chiama notifyAll () in questo caso, notifyAll () indurrà il risveglio (cioè la pianificazione) di un numero enorme di thread, molti dei quali inutilmente (poiché solo un thread può effettivamente procedere, cioè il thread a cui verrà concessa la monitor per l’object wait () , notify () o notifyAll () è stato chiamato), quindi sprecare risorse di calcolo.

Pertanto, se non si dispone di un’applicazione in cui un numero elevato di thread fa la stessa cosa contemporaneamente, si preferisca notifyAll () over notify () . Perché? Perché, come altri utenti hanno già risposto in questo forum, notifica ()

ritriggers un singolo thread che è in attesa sul monitor di questo object. […] La scelta è arbitraria e avviene a discrezione dell’implementazione.

fonte: Java SE8 API ( https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#notify– )

Immagina di avere un’applicazione del consumatore produttore in cui i consumatori sono pronti (cioè in attesa ) a consumare, i produttori sono pronti (cioè in attesa ) a produrre e la coda degli articoli (da produrre / consumare) è vuota. In tal caso, notify () potrebbe svegliare solo i consumatori e mai i produttori perché la scelta di chi si sveglia è arbitraria . Il ciclo del consumatore produttore non farebbe alcun progresso, sebbene produttori e consumatori siano pronti a produrre e consumare, rispettivamente. Invece, un utente viene svegliato (cioè lasciando lo stato wait () ), non prende un object fuori dalla coda perché è vuoto, e notify () s un altro consumatore per procedere.

Al contrario, notifyAll () risveglia sia i produttori che i consumatori. La scelta di chi è pianificata dipende dallo scheduler. Naturalmente, a seconda dell’implementazione dello scheduler, lo scheduler potrebbe anche pianificare solo i consumatori (ad esempio se assegni priorità ai thread di consumo). Tuttavia, il presupposto è che il pericolo che lo scheduler pianifichi solo i consumatori è inferiore al pericolo che la JVM svegli i consumatori solo perché ogni schedulatore ragionevolmente implementato non prende decisioni arbitrarie . Piuttosto, la maggior parte delle implementazioni degli scheduler fanno almeno un certo sforzo per prevenire la fame.

Sono molto sorpreso dal fatto che nessuno abbia menzionato il famigerato problema di “perdita di sonno” (google it).

Fondamentalmente:

  1. se hai più thread in attesa su una stessa condizione e,
  2. più thread che possono farti passare dallo stato A allo stato B e,
  3. più thread che possono farti passare dallo stato B allo stato A (di solito gli stessi thread come in 1.) e,
  4. la transizione dallo stato A a B dovrebbe notificare i thread in 1.

ALLORA si dovrebbe usare notifyAll a meno che non si abbia la certezza che le wakeup perse sono impossibili.

Un esempio comune è una coda FIFO concorrente in cui: più enqueuers (1. e 3. sopra) possono passare la coda da vuoti a non più vuoti dequeuers (2. sopra) possono attendere la condizione “la coda non è vuota” vuota -> non vuoto dovrebbe avvisare i dequeuer

Puoi facilmente scrivere un interleaving di operazioni in cui, partendo da una coda vuota, 2 encouer e 2 dequeuers interagiscono e 1 enqueuer rimarrà a dormire.

Questo è probabilmente un problema paragonabile al problema del deadlock.

Spero che questo chiarisca alcuni dubbi.

notify () : il metodo notify () triggers un thread in attesa del blocco (il primo thread che ha chiamato wait () su quel lock).

notifyAll () : il metodo notifyAll () ritriggers tutti i thread in attesa del lock; la JVM seleziona uno dei thread dall’elenco di thread in attesa del lock e lo risveglia.

Nel caso di un singolo thread in attesa di un blocco, non vi è alcuna differenza significativa tra notify () e notifyAll (). Tuttavia, quando c’è più di un thread in attesa del blocco, sia in notify () che notifyAll (), il thread esatto risvegliato è sotto il controllo della JVM e non è ansible controllare a livello di codice svegliando un thread specifico.

A prima vista, sembra una buona idea chiamare semplicemente notify () per ritriggersre un thread; potrebbe sembrare inutile svegliare tutti i thread. Tuttavia, il problema con notify () è che il thread risvegliato potrebbe non essere quello adatto per essere ritriggersto (il thread potrebbe essere in attesa di qualche altra condizione, o la condizione non è ancora soddisfatta per quel thread, ecc.). In tal caso , la notifica () potrebbe essere persa e nessun altro thread si sveglierà potenzialmente portando a un tipo di deadlock (la notifica viene persa e tutti gli altri thread sono in attesa di notifica per sempre).

Per evitare questo problema , è sempre meglio chiamare notifyAll () quando c’è più di un thread in attesa di un lock (o più di una condizione in cui viene effettuata l’attesa). Il metodo notifyAll () ritriggers tutti i thread, quindi non è molto efficiente. tuttavia, questa perdita di prestazioni è trascurabile nelle applicazioni del mondo reale.

Tutte le risposte di cui sopra sono corrette, per quanto posso dire, quindi ho intenzione di dirti qualcos’altro. Per il codice di produzione dovresti davvero usare le classi in java.util.concurrent. C’è molto poco che non possono fare per te, nell’area della concorrenza in Java.

Questa risposta è una riscrittura grafica e una semplificazione dell’eccellente risposta di xagyg , inclusi i commenti di eran .

Perché utilizzare notifyAll, anche quando ogni prodotto è destinato a un singolo consumatore?

Considerare produttori e consumatori, semplificati come segue.

Produttore:

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

Consumatore:

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

Assumi 2 produttori e 2 consumatori, condividendo un buffer di dimensione 1. L’immagine seguente mostra uno scenario che porta a un deadlock , che verrebbe evitato se tutti i thread usassero notifyAll .

Ogni notifica è etichettata con il thread che viene ritriggersto.

deadlock dovuto alla notifica

notify() si sveglierà un thread mentre notifyAll() si sveglierà tutto. Per quanto ne so non c’è via di mezzo. Ma se non sei sicuro di ciò che notify() farà ai tuoi thread, usa notifyAll() . Funziona come un fascino ogni volta.

notify() ti consente di scrivere codice più efficiente di notifyAll() .

Si consideri il seguente pezzo di codice che viene eseguito da più thread paralleli:

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

Può essere reso più efficiente utilizzando notify() :

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

Nel caso in cui si abbia un numero elevato di thread o se la condizione del ciclo di attesa sia costosa da valutare, notify() sarà significativamente più veloce di notifyAll() . Ad esempio, se si hanno 1000 thread, 999 thread verranno risvegliati e valutati dopo il primo notifyAll() , quindi 998, quindi 997 e così via. Al contrario, con la soluzione notify() , verrà risvegliato solo un thread.

Usa notifyAll() quando hai bisogno di scegliere quale thread farà il lavoro successivo:

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

Infine, è importante capire che in caso di notifyAll() , il codice all’interno dei blocchi synchronized che sono stati risvegliati verrà eseguito in sequenza, non tutti in una volta. Diciamo che ci sono tre thread che attendono nell’esempio sopra, e il quarto thread chiama notifyAll() . Tutti e tre i thread saranno risvegliati, ma solo uno inizierà l’esecuzione e controllerà le condizioni del ciclo while . Se la condizione è true , chiamerà di nuovo wait() e solo allora il secondo thread inizierà l’esecuzione e controllerà la sua condizione di ciclo while e così via.

Ecco una spiegazione più semplice:

Hai ragione nel dire che se usi notify () o notifyAll (), il risultato immediato è che esattamente un altro thread acquisirà il monitor e inizierà l’esecuzione. (Supponendo che alcuni thread siano stati bloccati in attesa () per questo object, altri thread non collegati non stanno assorbendo tutti i core disponibili, ecc.) L’impatto arriva più tardi.

Supponiamo che i thread A, B e C stessero aspettando questo object e che il thread A ottenga il monitor. La differenza sta in ciò che accade quando A rilascia il monitor. Se hai usato notify (), B e C sono ancora bloccati in attesa (): non stanno aspettando sul monitor, stanno aspettando di essere avvisati. Quando A rilascia il monitor, B e C rimarranno seduti lì, in attesa di una notifica ().

Se si è utilizzato notifyAll (), B e C hanno entrambi superato lo stato “wait for notification” e sono entrambi in attesa di acquisire il monitor. Quando A rilascia il monitor, B o C lo acquisiscono (presumendo che nessun altro thread sia in competizione per quel monitor) e iniziano l’esecuzione.

Tratto dal blog su Effective Java:

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

Quindi, quello che ho capito è (dal blog di cui sopra, commento di “Yann TM” su risposta accettata e documenti Java):

  • notify (): JVM risveglia uno dei thread in attesa su questo object. La selezione del filo è fatta arbitrariamente senza equità. Quindi lo stesso thread può essere risvegliato ancora e ancora. Lo stato del sistema cambia, ma non viene fatto alcun progresso reale. Così creando un livelock .
  • notifyAll (): JVM risveglia tutti i thread e quindi tutti i thread corrono per il lock su questo object. Ora, lo scheduler della CPU seleziona un thread che acquisisce il blocco su questo object. Questo processo di selezione sarebbe molto meglio della selezione di JVM. Quindi, garantendo vivacità.

Dai un’occhiata al codice pubblicato da @xagyg.

Supponiamo che due thread differenti stiano aspettando due condizioni diverse:
Il primo thread è in attesa di buf.size() != MAX_SIZE e il secondo thread è in attesa di buf.size() != 0 .

Supponiamo che a un certo punto buf.size() non sia uguale a 0 . JVM chiama notify() invece di notifyAll() e viene notificato il primo thread (non il secondo).

Il primo thread viene buf.size() , controlla buf.size() che potrebbe restituire MAX_SIZE e torna ad attendere. Il secondo thread non viene ritriggersto, continua ad attendere e non chiama get() .

notify() ritriggers il primo thread che ha chiamato wait() sullo stesso object.

notifyAll() ritriggers tutti i thread che hanno chiamato wait() sullo stesso object.

Il thread con la priorità più alta verrà eseguito per primo.

Vorrei menzionare ciò che è spiegato in Java Concurrency in Practice:

Primo punto, se Notificare o Notificare Tutto?

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

Se due thread A e B sono in attesa su predicati di condizioni diverse della stessa condizione, viene chiamata e notificata, quindi è su JVM a quale thread JVM verrà notificato.

Ora se notificare era inteso per il thread A e JVM notificato il thread B, quindi il thread B si sveglierà e vedrà che questa notifica non è utile, quindi aspetterà di nuovo. E il thread A non verrà mai a conoscenza di questo segnale mancato e qualcuno ha dirottato la sua notifica.

Quindi, chiamare notifyAll risolverà questo problema, ma di nuovo avrà un impatto sulle prestazioni poiché notificherà a tutti i thread e tutti i thread concorreranno per lo stesso lock e comporterà il cambio di contesto e quindi il carico sulla CPU. Ma dovremmo preoccuparci delle prestazioni solo se si comportano correttamente, se il comportamento in sé non è corretto, allora le prestazioni non servono.

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.