Lo sé, no es para nada grato intentar coordinar varias tareas en un programa multihilo. Cuando a mí me tocó, fue como tratar de orquestar una banda de músicos que nunca habían ensayado juntos: unos terminaban demasiado rápido, otros se quedaban atrás, en fin. Menos mal conocí java.util.concurrent.CountDownLatch y por fin pude solucionar todos mis problemas de sincronización. Así que voy a explicarte qué es y cómo funciona en aplicaciones multihilo, para que tú también evites esos molestos problemas de sincronización y coordines tus hilos como un profesional.
¿Qué es java.util.concurrent.CountDownLatch?
java.util.concurrent.CountDownLatch es una clase de sincronización que permite que uno o más hilos esperen hasta que otros hilos completen un conjunto de operaciones. A mí me ha servido bastante en aplicaciones multihilo, porque es ahí donde necesitas coordinar tareas paralelas antes de continuar con el flujo principal.
Entonces, al crear un objeto de CountDownLatch, lo que haces es definir un contador inicial que representa la cantidad de hilos que deben finalizar su tarea. Cada hilo decrementa este contador llamando al método countDown(). Una vez que el contador llega a cero, los hilos que estaban esperando con el método await() pueden continuar.
En palabras más simples, java.util.concurrent.CountDownLatch te ayuda a coordinar la ejecución de varios hilos, haciendo que unos hilos esperen mientras otros terminan su trabajo.
Cómo funciona java.util.concurrent.CountDownLatch
Sincronización de tareas
En este primer ejemplo que te he preparado, java.util.concurrent.CountDownLatch coordina la ejecución de tres hilos. Ten en cuenta que, cada hilo representa una tarea independiente que debe completarse antes de que el hilo principal pueda continuar.
import java.util.concurrent.CountDownLatch;
public class CountDownLatchExample {
public static void main(String[] args) throws InterruptedException {
// Crear un CountDownLatch con un contador de 3
CountDownLatch latch = new CountDownLatch(3);
// Crear tres tareas que se ejecutarán en paralelo
Runnable worker = () -> {
System.out.println(Thread.currentThread().getName() + " está trabajando...");
try {
Thread.sleep(2000); // Simula trabajo
System.out.println(Thread.currentThread().getName() + " terminó su tarea.");
latch.countDown(); // Decrementa el contador
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
};
// Iniciar tres hilos
new Thread(worker, "Hilo-1").start();
new Thread(worker, "Hilo-2").start();
new Thread(worker, "Hilo-3").start();
// El hilo principal espera hasta que los demás terminen
latch.await();
System.out.println("Todos los hilos han terminado. Continuando con la ejecución principal.");
}
}
Salida del programa:
Hilo-1 está trabajando...
Hilo-2 está trabajando...
Hilo-3 está trabajando...
Hilo-1 terminó su tarea.
Hilo-2 terminó su tarea.
Hilo-3 terminó su tarea.
Todos los hilos han terminado. Continuando con la ejecución principal.
Simulación de un sistema de carga
Ahora quiero que imagines que estás desarrollando un sistema donde varias tareas de inicialización deben completarse antes de que el sistema esté completamente listo. ¿Ya sabes cómo lo harías? Te lo muestro en este código:
import java.util.concurrent.CountDownLatch;
public class SystemStartup {
public static void main(String[] args) throws InterruptedException {
CountDownLatch startupLatch = new CountDownLatch(3);
Runnable task = (serviceName) -> {
try {
System.out.println(serviceName + " está iniciando...");
Thread.sleep((int) (Math.random() * 3000) + 1000);
System.out.println(serviceName + " está listo.");
startupLatch.countDown();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
};
// Crear hilos para simular servicios
new Thread(() -> task.run("Servicio A")).start();
new Thread(() -> task.run("Servicio B")).start();
new Thread(() -> task.run("Servicio C")).start();
// Esperar hasta que todos los servicios estén listos
startupLatch.await();
System.out.println("Todos los servicios están listos. El sistema está operativo.");
}
}
¿Cuándo deberías usar java.util.concurrent.CountDownLatch?
En aplicaciones con múltiples tareas que deben completarse antes de continuar:
- Procesamiento de imágenes: Imagina una aplicación que aplica varios filtros a una imagen (blanco y negro, desenfoque, etc.). Puedes usar CountDownLatch para que cada filtro se aplique en un hilo separado y el programa principal espere a que todos los filtros terminen antes de mostrar la imagen final.
- Descarga de archivos: Cuando vayas a descargar varios archivos de internet, puedes usar CountDownLatch para que cada archivo se descargue en un hilo separado y el programa principal espere a que todas las descargas finalicen antes de continuar.
Simulaciones:
- Simulación de un sistema de tráfico: Usa CountDownLatch para simular la llegada de vehículos a una intersección. Cada vehículo sería un hilo y el CountDownLatch se usaría para coordinar el paso de los vehículos por la intersección.
- Simulación de un juego multijugador: En un juego donde varios jugadores interactúan, CountDownLatch puede coordinar acciones como el inicio de una partida o la espera a que todos los jugadores estén listos.
Aplicaciones empresariales:
- Procesamiento de transacciones bancarias: Si un sistema bancario procesa múltiples transacciones simultáneamente, CountDownLatch se asegurará de que todas las transacciones se completen antes de actualizar el saldo de la cuenta.
- Sistemas de reservas: En una aplicación de reservas de vuelos o hoteles, CountDownLatch puede coordinar la disponibilidad de asientos o habitaciones, evitando que se produzcan sobreventas.
Ciencia e ingeniería:
- Análisis de datos: Si necesitas procesar grandes volúmenes de datos, puedes dividir la tarea en subtareas y usar CountDownLatch para coordinar el procesamiento de cada subtarea.
- Simulaciones científicas: En simulaciones de fenómenos físicos o químicos, CountDownLatch puede coordinar la interacción de diferentes componentes del sistema.
Que tu pasión por la programación no termine aquí, avanza rápidamente con nuestro Bootcamp de Java Full Stack de KeepCoding. Con nosotros, aprenderás desde lo básico hasta técnicas avanzadas que te abrirán las puertas al mundo IT.