CountDownLatch vs Semáforo


Hay alguna ventaja de usar

Java.útil.concurrente.CountdownLatch

En lugar de

Java.útil.concurrente.Semáforo?

Por lo que puedo decir, los siguientes fragmentos son casi equivalentes:

1. Semáforo

final Semaphore sem = new Semaphore(0);
for (int i = 0; i < num_threads; ++ i)
{
  Thread t = new Thread() {
    public void run()
    {
      try
      {
        doStuff();
      }
      finally
      {
        sem.release();
      }
    }
  };
  t.start();
}

sem.acquire(num_threads);

2: CountDownLatch

final CountDownLatch latch = new CountDownLatch(num_threads);
for (int i = 0; i < num_threads; ++ i)
{
  Thread t = new Thread() {
    public void run()
    {
      try
      {
        doStuff();
      }
      finally
      {
        latch.countDown();
      }
    }
  };
  t.start();
}

latch.await();

Excepto que en el caso #2 el pestillo no se puede reutilizar y lo más importante es que necesita saber de antemano cuántos hilos se crearán (o espere hasta que todos hayan comenzado antes de crear el pestillo.)

Entonces, ¿en qué situación podría ser preferible el pestillo?

Author: finnw, 2008-10-08

6 answers

El cierre de cuenta atrás se usa con frecuencia para exactamente lo contrario de su ejemplo. Generalmente, tendrías muchos hilos bloqueando en "await ()" que todos comenzarían simultáneamente cuando el conteo alcanzara cero.

final CountDownLatch countdown = new CountDownLatch(1);
for (int i = 0; i < 10; ++ i){
   Thread racecar = new Thread() {    
      public void run()    {
         countdown.await(); //all threads waiting
         System.out.println("Vroom!");
      }
   };
   racecar.start();
}
System.out.println("Go");
countdown.countDown();   //all threads start now!

También podría usar esto como una "barrera" de estilo MPI que hace que todos los subprocesos esperen a que otros subprocesos alcancen un cierto punto antes de continuar.

final CountDownLatch countdown = new CountDownLatch(num_thread);
for (int i = 0; i < num_thread; ++ i){
   Thread t= new Thread() {    
      public void run()    {
         doSomething();
         countdown.countDown();
         System.out.printf("Waiting on %d other threads.",countdown.getCount());
         countdown.await();     //waits until everyone reaches this point
         finish();
      }
   };
   t.start();
}

Dicho esto, el pestillo de cuenta RegreSiva se puede usar de forma segura de la manera que ha mostrado en su ejemplo.

 95
Author: James Schek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-02-21 19:53:16

CountDownLatch se usa para iniciar una serie de subprocesos y luego esperar hasta que todos estén completos (o hasta que llamen a countDown() un número determinado de veces.

El semáforo se usa para controlar el número de subprocesos concurrentes que están usando un recurso. Ese recurso puede ser algo así como un archivo, o podría ser la cpu limitando el número de subprocesos que se ejecutan. El conteo en un semáforo puede subir y bajar cuando diferentes hilos llaman acquire() y release().

En tu ejemplo, estás esencialmente usando Semáforo como una especie de CuentaUPLatch. Dado que tu intención es esperar a que terminen todos los hilos, usar CountdownLatch hace que tu intención sea más clara.

 62
Author: mtruesdell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-26 10:12:39

Breve resumen:

  1. Semaphore y CountDownLatch tienen un propósito diferente.

  2. Utilice Semáforo para controlar el acceso del hilo al recurso.

  3. Use CountDownLatch para esperar la finalización de todos los hilos

Semáforo definición de javadocs:

Un Semáforo mantiene un conjunto de permisos. Cada adquiere() bloques si es necesario hasta un permiso está disponible, y luego lo toma. Cada release() agrega un permiso, potencialmente liberando a un adquirente de bloqueo.

Sin embargo, no se utilizan objetos de permiso reales; el Semáforo solo mantiene un recuento del número disponible y actúa en consecuencia.

¿Cómo funciona ?

Los semáforos se usan para controlar el número de subprocesos concurrentes que están usando un recurso.Ese recurso puede ser algo así como un dato compartido, o un bloque de código (sección crítica) o cualquier archivo.

El conteo en un semáforo puede subir y bajar cuando diferentes hilos llaman acquire() y release(). Pero en cualquier punto del tiempo, no puede tener más número de hilos mayor que el recuento de semáforos.

Casos de uso de semáforos:

  1. Limitar el acceso concurrente al disco (esto puede matar el rendimiento debido a compitiendo disco busca)
  2. Limitación de creación de subprocesos
  3. Agrupación / limitación de conexiones JDBC
  4. Red regulación de la conexión
  5. Limitando tareas intensivas de CPU o memoria

Echa un vistazo a este artículo para usos de semáforos.

CountDownLatch definición de javadocs:

Una ayuda de sincronización que permite que uno o más subprocesos esperen hasta que se complete un conjunto de operaciones que se realizan en otros subprocesos.

¿Cómo funciona?

CountDownLatch funciona al tener un contador inicializado con número de hilos, que se decrementa cada vez que un hilo completa su ejecución. Cuando count llega a cero, significa que todos los subprocesos han completado su ejecución, y el subproceso que espera en latch reanuda la ejecución.

Casos de uso de CountDownLatch:

  1. Lograr el máximo Paralelismo: A veces queremos iniciar un número de hilos al mismo tiempo para lograr el máximo paralelismo
  2. Esperar N hilos a completarse antes de iniciar la ejecución
  3. Interbloqueo detección.

Echa un vistazo a este artículo para entender claramente los conceptos de CountDownLatch.

Echa un vistazo a Fork Join Poolen este artículo también. Tiene algunas similitudes con CountDownLatch .

 12
Author: Ravindra babu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-11-17 17:13:01

Digamos que entraste a golf pro shop, esperando encontrar un cuarteto,

Cuando haces cola para obtener un tee time de uno de los asistentes de pro shop, esencialmente llamas proshopVendorSemaphore.acquire(), una vez que obtienes un tee time, llamas proshopVendorSemaphore.release().Nota: cualquiera de los asistentes gratuitos puede servirle, es decir, recurso compartido.

Ahora te acercas a starter, él inicia un CountDownLatch(4) y llama await() para esperar a otros, por tu parte llamaste a check-in, es decir, CountDownLatch.countDown() y también lo hace el resto del cuarteto. Cuando todo arrive, starter gives go ahead (await() call returns)

Ahora, después de nueve hoyos cuando cada uno de ustedes toma un descanso, hipotéticamente permite involucrar a starter de nuevo, utiliza un 'nuevo' CountDownLatch(4) para dar el primer golpe en el Hoyo 10, la misma espera/sincronización que el Hoyo 1.

Sin embargo, si el starter usó un CyclicBarrier para comenzar, podría haber reiniciado la misma instancia en el Hoyo 10 en lugar de un segundo pestillo, que usa & throw.

 3
Author: Raj Srinivas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-17 18:24:21

Mirando la fuente disponible libremente, no hay magia en la implementación de las dos clases, por lo que su rendimiento debería ser más o menos el mismo. Elige el que haga que tu intención sea más obvia.

 1
Author: Tom Hawtin - tackline,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-07-27 14:24:50

CountDownLatch hace que los hilos esperen en el método await (), hasta que el conteo haya alcanzado cero. Así que tal vez quieras que todos tus hilos esperen hasta 3 invocaciones de algo, entonces todos los hilos pueden ir. Un pestillo generalmente no se puede restablecer.

Un semáforo permite que los subprocesos recuperen permisos, lo que evita que se ejecuten demasiados subprocesos a la vez, bloqueando si no puede obtener los permisos que requiere para continuar. Los permisos pueden ser devueltos a un Semáforo permitiendo que el otro esperando hilos para proceder.

 0
Author: Spencer Kormos,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-08 19:25:10