La classe Object in Java contiene tre metodi finali che consentono ai thread di comunicare sullo stato di blocco di una risorsa. Questi metodi sono wait(), notify() e notifyAll(). Quindi oggi guarderemo il programma di attesa, notifica e notifica di tutti in Java.
Attesa, notifica e notifica di tutti in Java
Il thread corrente che invoca questi metodi su qualsiasi oggetto dovrebbe avere il monitor dell’oggetto altrimenti viene generata un’eccezione java.lang.IllegalMonitorStateException.
wait
I metodi di attesa dell’oggetto hanno tre varianti, una delle quali attende indefinitamente che un altro thread chiami il metodo notify o notifyAll sull’oggetto per svegliare il thread corrente. Le altre due varianti mettono il thread corrente in attesa per un periodo di tempo specifico prima di svegliarsi.
notify
Il metodo notify risveglia solo un thread in attesa sull’oggetto e quel thread inizia l’esecuzione. Quindi, se ci sono più thread in attesa di un oggetto, questo metodo ne risveglierà solo uno. La scelta del thread da risvegliare dipende dall’implementazione del sistema operativo della gestione dei thread.
notifyAll
Il metodo notifyAll risveglia tutti i thread in attesa sull’oggetto, sebbene quale di essi processerà per primo dipenda dall’implementazione del sistema operativo. Questi metodi possono essere utilizzati per implementare il problema del produttore consumatore dove i thread consumatori sono in attesa degli oggetti in coda e i thread produttori inseriscono oggetti in coda e notificano i thread in attesa. Vediamo un esempio in cui più thread lavorano sullo stesso oggetto e utilizziamo i metodi wait, notify e notifyAll.
Messaggio
A java bean class on which threads will work and call wait and notify methods.
package com.journaldev.concurrency;
public class Message {
private String msg;
public Message(String str){
this.msg=str;
}
public String getMsg() {
return msg;
}
public void setMsg(String str) {
this.msg=str;
}
}
Cameriere
A class that will wait for other threads to invoke notify methods to complete it’s processing. Notice that Waiter thread is owning monitor on Message object using synchronized block.
package com.journaldev.concurrency;
public class Waiter implements Runnable{
private Message msg;
public Waiter(Message m){
this.msg=m;
}
@Override
public void run() {
String name = Thread.currentThread().getName();
synchronized (msg) {
try{
System.out.println(name+" waiting to get notified at time:"+System.currentTimeMillis());
msg.wait();
}catch(InterruptedException e){
e.printStackTrace();
}
System.out.println(name+" waiter thread got notified at time:"+System.currentTimeMillis());
//processa il messaggio ora
System.out.println(name+" processed: "+msg.getMsg());
}
}
}
Notifier
A class that will process on Message object and then invoke notify method to wake up threads waiting for Message object. Notice that synchronized block is used to own the monitor of Message object.
package com.journaldev.concurrency;
public class Notifier implements Runnable {
private Message msg;
public Notifier(Message msg) {
this.msg = msg;
}
@Override
public void run() {
String name = Thread.currentThread().getName();
System.out.println(name+" started");
try {
Thread.sleep(1000);
synchronized (msg) {
msg.setMsg(name+" Notifier work done");
msg.notify();
// msg.notifyAll();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
WaitNotifyTest
Classe di test che creerà più thread di Waiter e Notifier e li avvierà.
package com.journaldev.concurrency;
public class WaitNotifyTest {
public static void main(String[] args) {
Message msg = new Message("process it");
Waiter waiter = new Waiter(msg);
new Thread(waiter,"waiter").start();
Waiter waiter1 = new Waiter(msg);
new Thread(waiter1, "waiter1").start();
Notifier notifier = new Notifier(msg);
new Thread(notifier, "notifier").start();
System.out.println("All the threads are started");
}
}
Quando invocheremo il programma sopra, vedremo l’output seguente ma il programma non si completerà perché ci sono due thread in attesa sull’oggetto Message e il metodo notify() ha risvegliato solo uno di essi, l’altro thread è ancora in attesa di essere notificato.
waiter waiting to get notified at time:1356318734009
waiter1 waiting to get notified at time:1356318734010
All the threads are started
notifier started
waiter waiter thread got notified at time:1356318735011
waiter processed: notifier Notifier work done
Se commentiamo la chiamata a notify() e decommentiamo la chiamata a notifyAll() nella classe Notifier, l’output prodotto sarà il seguente.
waiter waiting to get notified at time:1356318917118
waiter1 waiting to get notified at time:1356318917118
All the threads are started
notifier started
waiter1 waiter thread got notified at time:1356318918120
waiter1 processed: notifier Notifier work done
waiter waiter thread got notified at time:1356318918120
waiter processed: notifier Notifier work done
Poiché il metodo notifyAll() risveglia entrambi i thread Waiter, il programma si completa e termina dopo l’esecuzione. Questo è tutto per wait, notify e notifyAll in Java.
Source:
https://www.digitalocean.com/community/tutorials/java-thread-wait-notify-and-notifyall-example