La clase Object en Java contiene tres métodos finales que permiten que los hilos se comuniquen sobre el estado del bloqueo de un recurso. Estos métodos son wait(), notify() y notifyAll(). Así que hoy veremos el uso de wait, notify y notifyAll en un programa Java.
wait, notify y notifyAll en Java
El hilo actual que invoca estos métodos en cualquier objeto debe tener el monitor del objeto, de lo contrario lanzará una excepción java.lang.IllegalMonitorStateException.
wait
Los métodos de espera del objeto tienen tres variantes, una que espera indefinidamente a que otro hilo llame a los métodos notify o notifyAll en el objeto para despertar al hilo actual. Las otras dos variantes hacen que el hilo actual espere durante un tiempo específico antes de despertar.
notify
El método notify despierta solo un hilo esperando en el objeto y ese hilo comienza su ejecución. Por lo tanto, si hay varios hilos esperando un objeto, este método despertará solo a uno de ellos. La elección del hilo a despertar depende de la implementación del sistema operativo en la gestión de hilos.
notifyAll
El método notifyAll despierta a todos los hilos que están esperando en el objeto, aunque el orden en que se procesen depende de la implementación del sistema operativo. Estos métodos pueden utilizarse para implementar el problema del productor-consumidor, donde los hilos consumidores esperan los objetos en la cola y los hilos productores colocan objetos en la cola y notifican a los hilos en espera. Veamos un ejemplo en el que varios hilos trabajan en el mismo objeto y utilizamos los métodos wait, notify y notifyAll.
Mensaje
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;
}
}
Esperador
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());
//procesar el mensaje ahora
System.out.println(name+" processed: "+msg.getMsg());
}
}
}
Notificador
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();
}
}
}
PruebaEsperaNotificación
Clase de prueba que creará varios hilos de Espera y Notificador y los iniciará.
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");
}
}
Cuando invoquemos el programa anterior, veremos la siguiente salida, pero el programa no se completará porque hay dos hilos esperando en el objeto Mensaje y el método notify() solo ha despertado a uno de ellos, el otro hilo todavía está esperando ser notificado.
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
Si comentamos la llamada a notify() y descomentamos la llamada a notifyAll() en la clase Notificador, se producirá la siguiente salida.
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
Dado que el método notifyAll() despierta a ambos hilos Espera y el programa se completa y termina después de la ejecución. Eso es todo para esperar, notificar y notificarTodo en Java.
Source:
https://www.digitalocean.com/community/tutorials/java-thread-wait-notify-and-notifyall-example