Guía práctica para entender y aplicar notifyAll() en Java

| Última modificación: 4 de diciembre de 2024 | Tiempo de Lectura: 3 minutos

Algunos de nuestros reconocimientos:

Premios KeepCoding

¿Ya empezaste a trabajar con hilos y sincronización en Java y te ha parecido muy complejo? Puede que necesites entender y aplicar notifyAll() en Java. No te presentaría este método si no fuese importante y si no te facilitara las cosas en la programación concurrente. Créeme, notifyAll() te ayudará muchísimo cuando tengas varios hilos que necesiten ser notificados simultáneamente.

notifyAll() en Java qué es

¿Qué es notifyAll() en Java?

El método notifyAll() en Java se creó para despertar todos los hilos que están esperando en un objeto en particular. Una forma fácil de entenderlo sería primero que recuerdes que, cuando un hilo ejecuta código que está sincronizado (es decir, cuando accede a un bloque de código sincronizado o a un método sincronizado), puede llamar a wait() en un objeto. Esto hace que el hilo entre en un estado de espera hasta que otro hilo lo despierte.

Entonces, mientras que notify() despierta solo un hilo que está esperando, notifyAll() despierta a todos los hilos que están esperando en el objeto.

¿Por qué elegir notifyAll() en lugar de notify()?

Voy a plantearte los contextos en los que puedes usar tanto notify() como notifyAll() en Java, porque ambos tienen propósitos similares, pero no son iguales:

  • notify(): Despierta a un solo hilo que está esperando en el objeto. Sirve más en términos de recursos porque solo se despierta un hilo, lo que reduce el consumo de memoria y CPU. Sin embargo, no te lo recomiendo si tienes varios hilos esperando y necesitas que todos continúen su ejecución, ya que uno solo se despertará.
  • notifyAll(): La palabra “all” indica que este método despierta a todos los hilos que están esperando en el objeto. Te servirá bastante cuando tengas varios hilos esperando a una condición que, una vez cumplida, permite que todos los hilos continúen. Lo único es que el rendimiento no será tan bueno, porque todos los hilos son despertados y se consumen más recursos.

¿Cuándo usar notifyAll() en Java?

  • Condiciones de trabajo compartido: Si tienes múltiples hilos esperando una condición similar, pero cada uno con tareas distintas que hacer una vez que se cumpla la condición, mejor usa notifyAll().
  • Sistemas de trabajo paralelo: Si varios hilos necesitan realizar la misma tarea o un conjunto de tareas similares, y no importa el orden en que se despierten, entonces notifyAll() en Java puede ser la mejor opción.

Ejemplo práctico de notifyAll() en Java

Te planteo esta situación: Vas a crear un sistema de monitoreo para un servidor de datos. En este sistema, varios hilos están esperando que se actualicen los datos para procesarlos.

Te en cuenta que, cada hilo podría estar esperando una condición diferente (por ejemplo, un tipo específico de dato), pero todos deben continuar su trabajo cuando los datos estén actualizados.

Lo que harás será usar notifyAll() en Java, para despertar a todos los hilos, mientras espera la actualización de los datos.

Con este código te muestro cómo funciona notifyAll():

class Server extends Thread {
public void run() {
synchronized (this) {
System.out.println(Thread.currentThread().getName() + " esperando datos...");
try {
this.wait(); // El hilo se pone en espera
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " procesando datos.");
}
}
}

class DataUpdater extends Thread {
Server server;

DataUpdater(Server server) {
this.server = server;
}

public void run() {
synchronized (server) {
System.out.println(Thread.currentThread().getName() + " actualizando datos...");
server.notifyAll(); // Despierta a todos los hilos esperando
System.out.println(Thread.currentThread().getName() + " datos actualizados.");
}
}
}

public class MainClass {
public static void main(String[] args) throws InterruptedException {
Server server = new Server();
DataUpdater dataUpdater = new DataUpdater(server);

Thread t1 = new Thread(server, "Hilo-1");
Thread t2 = new Thread(server, "Hilo-2");
Thread t3 = new Thread(dataUpdater, "Actualizador");

t1.start();
t2.start();
Thread.sleep(100); // Aseguramos que los hilos de servidor estén esperando
t3.start(); // El actualizador de datos despierta a todos los hilos
}
}

Salida esperada:

Hilo-1 esperando datos...
Hilo-2 esperando datos...
Actualizador actualizando datos...
Actualizador datos actualizados.
Hilo-1 procesando datos.
Hilo-2 procesando datos.

Si notaste bien, notifyAll() lo que hizo fue despertar tanto a Hilo-1 como a Hilo-2, permitiendo que ambos continúen con su trabajo.

Diferencias entre notify() y notifyAll()

Si aún no te ha quedado muy claro, te hice esta tabla comparativa para mostrarte las diferencias entre ambos métodos y sea más fácil para ti este camino de aprender a programar con Java:

Aspectonotify()notifyAll()
NotificaciónDespierta solo un hilo.Despierta todos los hilos que están esperando.
RendimientoMás eficiente en cuanto a recursos (menos CPU y memoria).Menos eficiente, consume más recursos.
RiesgoHay un mayor riesgo de que un hilo se pierda si no es el seleccionado.Menos riesgo, ya que se despiertan todos los hilos.
Uso recomendadoCuando solo un hilo debe proceder.Cuando varios hilos deben proceder simultáneamente.

En el Bootcamp de Java Full Stack de KeepCoding aprenderás a manejar no solo notifyAll(), sino también otras técnicas avanzadas de programación en Java que te permitirán desarrollar aplicaciones robustas y escalables. ¡No dejes pasar esta oportunidad de transformar tu carrera y convertirte en un experto en Java!

Ramón Maldonado

Full Stack Developer y Responsable de Formación base en KeepCoding.

Posts más leídos

¡CONVOCATORIA ABIERTA!

Java y Spring Boot

Full Stack Bootcamp

Clases en Directo | Profesores en Activo | Temario 100% actualizado