¿Qué es java.util.concurrent.CyclicBarrier y cómo se utiliza en Java?

| Última modificación: 24 de enero de 2025 | Tiempo de Lectura: 3 minutos

Algunos de nuestros reconocimientos.:

Sufrí bastante una vez que me tocó trabajar en un proyecto donde cada módulo de cálculo debía completarse antes de combinar los resultados y avanzar. La verdad no tenía ni idea de cómo asegurar que todos los hilos terminaran al mismo tiempo. Un amigo muy cercano fue quien me instruyó sobre java.util.concurrent.CyclicBarrier y terminó con ese sufrimiento. Ya con esta clase ahora sí pude sincronizar los procesos y optimizar el flujo de trabajo. Hoy también quiero ser un gran amigo para ti y explicarte qué es y cómo se utiliza CyclicBarrier correctamente en Java.

java.util.concurrent.CyclicBarrier qué es

¿Qué es java.util.concurrent.CyclicBarrier?

Se me ocurre que pienses en alpinistas escalando una montaña. Por si no lo sabías, para garantizar la seguridad de todos, ellos tienen que llegar a ciertos puntos de control juntos, reagruparse y comprobar su equipo antes de continuar.

Entonces, java.util.concurrent.CyclicBarrier sería como un puesto de control, donde múltiples hilos (alpinistas) se sincronizan y avanzan en conjunto.

Siempre recuerda que java.util.concurrent.CyclicBarrier sincroniza múltiples hilos para que esperen unos a otros antes de avanzar. Sirve bastante cuando cada hilo realiza una tarea independiente y sus resultados deben combinarse en un paso posterior. Además, CyclicBarrier se puede reutilizar después de liberar a los hilos, lo cual lo diferencia de CountDownLatch.

Métodos de CyclicBarrier

  • getParties(): Devuelve el número total de hilos que la barrera está esperando.
  • getNumberWaiting(): Indica cuántos hilos están esperando en la barrera.
  • reset(): Restablece la barrera a su estado inicial.
  • isBroken(): Verifica si la barrera está rota (por interrupciones o tiempo de espera agotado).

Diferencias entre CyclicBarrier y CountDownLatch

AspectoCyclicBarrierCountDownLatch
ReutilizableNo
Número fijo de hilosRequiere un número fijoNo necesariamente
Acción opcionalPuede ejecutar una acción comúnNo tiene acción asociada

Cómo funciona java.util.concurrent.CyclicBarrier

Voy a dejarte 3 pasos que siempre tienes que incluir para que java.util.concurrent.CyclicBarrier funcione correctamente:

  1. Definición de la barrera: Se crea un objeto CyclicBarrier especificando cuántos hilos deben llegar al punto de sincronización.
  2. Espera en la barrera: Cada hilo realiza su tarea y luego llama al método await(). Esto detiene el hilo hasta que todos los demás hilos lleguen al mismo punto.
  3. Liberación: Una vez que todos los hilos alcanzan la barrera, se ejecuta cualquier acción asociada, si está definida, y luego los hilos pueden continuar.

Sincronización básica entre hilos

Piensa que tienes tres hilos que deben completar cálculos independientes antes de proceder juntos.

import java.util.concurrent.CyclicBarrier;

public class CyclicBarrierExample {
public static void main(String[] args) {
CyclicBarrier barrier = new CyclicBarrier(3, () ->
System.out.println("Todos los hilos han llegado a la barrera. Continuando..."));

Runnable task = () -> {
try {
System.out.println(Thread.currentThread().getName() + " está procesando...");
Thread.sleep((int) (Math.random() * 2000));
System.out.println(Thread.currentThread().getName() + " alcanzó la barrera.");
barrier.await();
} catch (Exception e) {
e.printStackTrace();
}
};

new Thread(task, "Hilo-1").start();
new Thread(task, "Hilo-2").start();
new Thread(task, "Hilo-3").start();
}
}

Te explico:

  • Aquí ves que tres hilos realizan tareas independientes.
  • Una vez que todos llegan a la barrera (llaman a await()), se ejecuta una acción definida (en este caso, un mensaje) antes de que los hilos continúen.

Simulación de carga de módulos

Aquí te voy a mostrar un ejemplo que simula una aplicación que necesita cargar varios módulos antes de iniciar el sistema.

import java.util.concurrent.CyclicBarrier;

public class ModuleLoader {
public static void main(String[] args) {
CyclicBarrier barrier = new CyclicBarrier(4, () ->
System.out.println("Todos los módulos han sido cargados. Sistema listo."));

Runnable moduleTask = (module) -> {
try {
System.out.println(module + " se está cargando...");
Thread.sleep((int) (Math.random() * 3000));
System.out.println(module + " cargado.");
barrier.await();
} catch (Exception e) {
e.printStackTrace();
}
};

new Thread(() -> moduleTask.run("Módulo A")).start();
new Thread(() -> moduleTask.run("Módulo B")).start();
new Thread(() -> moduleTask.run("Módulo C")).start();
new Thread(() -> moduleTask.run("Módulo D")).start();
}
}

¿Qué sucedió aquí?

  • Si lo notaste bien, cuatro módulos se cargan de forma paralela.
  • Una vez que todos están listos, el sistema se inicializa.

Cuándo usar java.util.concurrent.CyclicBarrier

  1. Para cálculos distribuidos: Mi consejo es que lo uses cuando los resultados de tareas paralelas deban combinarse.
  2. Sincronización compleja: En situaciones donde múltiples hilos deben coordinarse en varios puntos, será de gran ayuda.
  3. Sistemas modulares: Ideal para que te asegures de que todos los módulos estén listos antes de continuar.

Enhorabuena has aprendido a usar java.util.concurrent.CyclicBarrier. Ya te quedó más que claro que es una herramienta poderosa para sincronizar múltiples hilos y asegurarte de que trabajen de manera coordinada. Ahora que ya sabes cómo funciona, pienso que lo puedes poner en práctica para crear aplicaciones complejas que funcionen de maravilla.

¿Esto solo fue un abrebocas para ti? ¿Te quedó faltando la parte práctica? Pues simplemente apúntate al Bootcamp de Java Full Stack de KeepCoding. Te enseñaremos desde lo esencial hasta lo avanzado, preparándote para triunfar en el sector IT. ¡El momento de transformar tu carrera es ahora!

Posts más leídos