¿Alguien puede ayudarme a comprender qué CountDownLatch
es Java y cuándo usarlo?
No tengo una idea muy clara de cómo funciona este programa. Según tengo entendido, los tres subprocesos comienzan a la vez y cada subproceso llamará a CountDownLatch después de 3000 ms. Entonces la cuenta regresiva disminuirá uno por uno. Después de que el pestillo se vuelve cero, el programa imprime "Completado". Tal vez la forma en que entendí es incorrecta.
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
class Processor implements Runnable {
private CountDownLatch latch;
public Processor(CountDownLatch latch) {
this.latch = latch;
}
public void run() {
System.out.println("Started.");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
latch.countDown();
}
}
// ------------------------------------------------ -----
public class App {
public static void main(String[] args) {
CountDownLatch latch = new CountDownLatch(3); // coundown from 3 to 0
ExecutorService executor = Executors.newFixedThreadPool(3); // 3 Threads in pool
for(int i=0; i < 3; i++) {
executor.submit(new Processor(latch)); // ref to latch. each time call new Processes latch will count down by 1
}
try {
latch.await(); // wait until latch counted down to 0
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Completed.");
}
}
Respuestas:
Sí, entendiste correctamente.
CountDownLatch
funciona en el principio de cierre, el hilo principal esperará hasta que la puerta esté abierta. Un subproceso espera n subprocesos, especificados al crear elCountDownLatch
.Cualquier hilo, generalmente el hilo principal de la aplicación, cuyas llamadas
CountDownLatch.await()
esperarán hasta que el recuento llegue a cero o sea interrumpido por otro hilo. Todos los otros subprocesos deben realizar una cuenta regresiva llamandoCountDownLatch.countDown()
una vez que estén completos o listos.Tan pronto como el recuento llegue a cero, el hilo de espera continúa. Una de las desventajas / ventajas de
CountDownLatch
es que no es reutilizable: una vez que el recuento llega a cero, ya no puede usarloCountDownLatch
.Editar:
Úselo
CountDownLatch
cuando un subproceso (como el subproceso principal) requiere esperar a que uno o más subprocesos se completen, antes de que pueda continuar el procesamiento.Un ejemplo clásico de uso
CountDownLatch
en Java es una aplicación Java central del lado del servidor que usa arquitectura de servicios, donde múltiples servicios son provistos por múltiples hilos y la aplicación no puede comenzar a procesarse hasta que todos los servicios se hayan iniciado con éxito.La pregunta de PS OP tiene un ejemplo bastante sencillo, así que no incluí uno.
fuente
One thread waits for n number of threads specified while creating CountDownLatch in Java
. Si necesita dicho mecanismo, entonces es prudente usarloCyclicBarrier
. La diferencia conceptual fundamental entre estos dos, como se da enJava concurrency in Practice
es:Latches are for waiting for events; barriers are for waiting for other threads
.cyclicBarrier.await()
entra en un estado de bloqueo.CountDownLatch
en Java es un tipo de sincronizador que permiteThread
esperar uno o másThread
segundos antes de comenzar a procesar.CountDownLatch
funciona según el principio de cierre, el hilo esperará hasta que la puerta esté abierta. Un subproceso espera eln
número de subprocesos especificados durante la creaciónCountDownLatch
.p.ej
final CountDownLatch latch = new CountDownLatch(3);
Aquí ponemos el contador a 3.
Cualquier hilo, generalmente el hilo principal de la aplicación, cuyas llamadas
CountDownLatch.await()
esperarán hasta que el recuento llegue a cero o sea interrumpido por otroThread
. Todos los otros subprocesos deben realizar una cuenta regresiva llamandoCountDownLatch.countDown()
una vez que se hayan completado o estén listos para el trabajo. Tan pronto como el recuento llegue a cero, laThread
espera comenzará a correr.Aquí el recuento se reduce por
CountDownLatch.countDown()
método.El
Thread
que llama alawait()
método esperará hasta que el recuento inicial llegue a cero.Para hacer el recuento cero, otros hilos necesitan llamar al
countDown()
método. Una vez que el recuento llegue a cero, el hilo que invocó elawait()
método se reanudará (comenzará su ejecución).La desventaja
CountDownLatch
es que no es reutilizable: una vez que el recuento se vuelve cero, ya no se puede usar.fuente
new CountDownLatch(3)
ya que tenemos 3 hilos de lonewFixedThreadPool
definido?NikolaB lo explicó muy bien, sin embargo, un ejemplo sería útil de entender, así que aquí hay un ejemplo simple ...
fuente
Se usa cuando queremos esperar a más de un hilo para completar su tarea. Es similar unirse en hilos.
Donde podemos usar CountDownLatch
Considere un escenario en el que tenemos requisitos donde tenemos tres hilos "A", "B" y "C" y queremos comenzar el hilo "C" solo cuando los hilos "A" y "B" completan o completan parcialmente su tarea.
Se puede aplicar al escenario de TI del mundo real
Considere un escenario en el que el gerente dividió los módulos entre los equipos de desarrollo (A y B) y quiere asignarlo al equipo de control de calidad para probar solo cuando ambos equipos completen su tarea.
La salida del código anterior será:
Tarea asignada al equipo de desarrollo devB
Tarea asignada al equipo de desarrollo devA
Tarea finalizada por el equipo de desarrollo devB
Tarea finalizada por el equipo de desarrollo devA
Tarea asignada al equipo de control de calidad
Tarea finalizada por el equipo de control de calidad
Aquí aguardan () espera del procedimiento para la bandera countdownlatch para convertirse en 0, y cuenta atrás () método decrementa bandera countdownlatch por 1.
Limitación de JOIN: el ejemplo anterior también se puede lograr con JOIN, pero JOIN no se puede usar en dos escenarios:
fuente
CoundDownLatch le permite hacer que un hilo espere hasta que todos los otros hilos hayan terminado su ejecución.
El pseudocódigo puede ser:
fuente
Un buen ejemplo de cuándo usar algo como esto es con Java Simple Serial Connector, accediendo a los puertos seriales. Por lo general, escribirá algo en el puerto y, de forma asíncrona, en otro hilo, el dispositivo responderá en un SerialPortEventListener. Por lo general, querrás pausar después de escribir en el puerto para esperar la respuesta. Manejar los bloqueos de hilo para este escenario manualmente es extremadamente complicado, pero usar Countdownlatch es fácil. Antes de pensar que puedes hacerlo de otra manera, ¡ten cuidado con las condiciones de carrera en las que nunca pensaste!
Pseudocódigo:
fuente
Si agrega alguna depuración después de su llamada a latch.countDown (), esto puede ayudarlo a comprender mejor su comportamiento.
La salida mostrará que el conteo se está decrementando. Este 'conteo' es efectivamente el número de tareas Ejecutables (objetos del procesador) que ha comenzado contra las cuales countDown () no ha sido invocado y, por lo tanto, está bloqueado el hilo principal en su llamada a latch.await ().
fuente
De la documentación de Oracle sobre CountDownLatch :
A
CountDownLatch
se inicializa con un recuento dado. Losawait
métodos se bloquean hasta que el recuento actual llega a cero debido a las invocaciones delcountDown()
método, después de lo cual se liberan todos los subprocesos en espera y cualquier invocación posterior de espera de retorno inmediatamente. Este es un fenómeno de una sola vez: el recuento no se puede restablecer.Un
CountDownLatch
inicializado con un recuento de uno sirve como un simple pestillo de encendido / apagado, o puerta: todos los hilos que invocan esperan en la puerta hasta que se abre por un hilo que invoca countDown ().Un
CountDownLatch
inicializado a N puede usarse para hacer que un subproceso espere hasta que N subprocesos hayan completado alguna acción, o alguna acción se haya completado N veces.Si el recuento actual es cero, este método vuelve inmediatamente.
Si el recuento actual es mayor que cero, entonces se reduce. Si el nuevo recuento es cero, todos los hilos en espera se vuelven a habilitar para fines de programación de hilos.
Explicación de tu ejemplo.
Ha establecido el recuento como 3 para
latch
variableHas pasado este
latch
hilo compartido a Trabajador:Processor
Runnable
instancias deProcessor
ExecutorService
executor
El subproceso principal (
App
) está esperando que el recuento se vuelva cero con la siguiente declaraciónProcessor
el hilo duerme durante 3 segundos y luego disminuye el valor de conteo conlatch.countDown()
La primera
Process
instancia cambiará el recuento de pestillos como 2 después de su finalización debido alatch.countDown()
.La segunda
Process
instancia cambiará el recuento de bloqueos como 1 después de que se complete debido alatch.countDown()
.La tercera
Process
instancia cambiará el recuento de bloqueo como 0 después de que se complete debido alatch.countDown()
.El conteo cero en el pestillo hace que el hilo principal
App
salga deawait
El programa de aplicación imprime esta salida ahora:
Completed
fuente
Este ejemplo de Java Doc me ayudó a comprender los conceptos claramente:
Interpretación visual:
Evidentemente,
CountDownLatch
permite que un subproceso (aquíDriver
) espere hasta que se terminen varios subprocesos en ejecución (aquíWorker
) con su ejecución.fuente
Como se menciona en JavaDoc ( https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CountDownLatch.html ), CountDownLatch es una ayuda de sincronización, introducida en Java 5. Aquí la sincronización no significa restringir el acceso a una sección crítica. Sino más bien secuencias de acciones de diferentes hilos. El tipo de sincronización logrado a través de CountDownLatch es similar al de Join. Suponga que hay un subproceso "M" que necesita esperar a que otros subprocesos de trabajo "T1", "T2", "T3" completen sus tareas Antes de Java 1.5, la forma en que esto se puede hacer es que M ejecute el siguiente código
El código anterior se asegura de que el hilo M reanude su trabajo después de que T1, T2, T3 completen su trabajo. T1, T2, T3 pueden completar su trabajo en cualquier orden. Lo mismo se puede lograr a través de CountDownLatch, donde T1, T2, T3 y el hilo M comparten el mismo objeto CountDownLatch.
Solicitudes "M":
countDownLatch.await();
donde como "T1", "T2", "T3"
countDownLatch.countdown();
Una desventaja con el método de unión es que M tiene que saber acerca de T1, T2, T3. Si hay un nuevo subproceso de trabajo T4 agregado más tarde, M también debe tenerlo en cuenta. Esto se puede evitar con CountDownLatch. Después de la implementación, la secuencia de acción sería [T1, T2, T3] (el orden de T1, T2, T3 podría ser de todos modos) -> [M]
fuente
El mejor ejemplo en tiempo real para countDownLatch explicado en este enlace CountDownLatchExample
fuente
fuente