Pregunta

¿Hay alguna ventaja de usar

java.util.concurrent .CountdownLatch

en lugar de

java.util.concurrent .Semaphore ?

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 n. ° 2, el pestillo no se puede reutilizar y, lo que es más importante, debe saber de antemano cuántos subprocesos se crearán (o esperar hasta que todos se inicien antes de crear el pestillo).

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

¿Fue útil?

Solución

El pestillo CountDown se usa con frecuencia para el opuesto exacto de su ejemplo. En general, tendrías muchos hilos bloqueados en " await () " todo comenzaría simultáneamente cuando la ciudad llegara a 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 eso hace que todos los hilos esperen a que otros hilos se pongan al día hasta 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 todo esto, el pestillo CountDown se puede usar de forma segura de la manera que ha mostrado en su ejemplo.

Otros consejos

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

Semaphore se usa para controlar el número de subprocesos concurrentes que están utilizando un recurso. Ese recurso puede ser algo así como un archivo, o podría ser la CPU al limitar el número de subprocesos que se ejecutan. El recuento de un semáforo puede aumentar o disminuir a medida que diferentes hilos llaman a adquirir () y release () .

En su ejemplo, esencialmente está utilizando Semaphore como una especie de Latch Count UP . Dado que su intención es esperar a que finalicen todos los hilos, el uso del CountdownLatch aclara su intención.

Breve resumen:

  1. Semáforo y CountDownLatch tiene un propósito diferente.

  2. Utilice Semáforo para controlar el acceso de subprocesos 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 adquirir () bloquea si es necesario hasta que un permiso esté disponible, y luego lo toma. Cada versión () agrega un permiso, liberando potencialmente 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 utilizan para controlar la cantidad de subprocesos concurrentes que utilizan un recurso. Ese recurso puede ser algo así como datos compartidos, o un bloque de código ( sección crítica ) o cualquier archivo.

La cuenta en un semáforo puede subir y bajar a medida que diferentes hilos llaman a adquirir () y liberar (). Pero en cualquier momento, no puede tener más hilos 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 el disco de la competencia busca)
  2. Limitación de creación de subprocesos
  3. Agrupación / limitación de conexiones JDBC
  4. Limitación de la conexión de red
  5. Acelerando CPU o tareas intensivas en memoria

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

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 en otros subprocesos.

¿Cómo funciona?

CountDownLatch funciona teniendo un contador inicializado con un número de subprocesos, que disminuye cada vez que un subproceso completa su ejecución. Cuando el recuento llega a cero, significa que todos los subprocesos han completado su ejecución, y el subproceso que espera en el pestillo reanuda la ejecución.

Casos de uso de CountDownLatch:

  1. Alcanzar el paralelismo máximo: a veces queremos comenzar una serie de hilos al mismo tiempo para lograr el máximo paralelismo
  2. Espere a que se completen N subprocesos antes de iniciar la ejecución
  3. Detección de punto muerto.

Eche un vistazo a este artículo para comprender los conceptos de CountDownLatch claramente.

Eche un vistazo a Fork Join Pool en este artículo también . Tiene algunas similitudes con CountDownLatch .

Digamos que entraste a la tienda de golf profesional con la esperanza de encontrar un cuarteto,

Cuando hace cola para obtener un tee time de uno de los asistentes de la tienda profesional, esencialmente llama a proshopVendorSemaphore.acquire () , una vez que obtiene un tee time, llama a proshopVendorSemaphore .release () .Nota: cualquiera de los asistentes gratuitos puede atenderlo, es decir, recursos compartidos.

Ahora camina hacia el arranque, él inicia un CountDownLatch (4) y llama a await () para esperar a los demás, por su parte a la que llamó check-in, es decir CountDownLatch . countDown () y también el resto del grupo. Cuando todo llega, el iniciador da el visto bueno ( await () call return)

Ahora, después de nueve hoyos cuando cada uno de ustedes toma un descanso, hipotéticamente permite involucrar al iniciador nuevamente, usa un 'nuevo' CountDownLatch (4) para comenzar el hoyo 10, la misma espera / sincronización que Hoyo 1.

Sin embargo, si el iniciador usó un CyclicBarrier para empezar, podría haber restablecido la misma instancia en el Hoyo 10 en lugar de un segundo pestillo, que usa & amp; tirar.

Mirando la fuente disponible gratuitamente, no hay magia en la implementación de las dos clases, por lo que su rendimiento debería ser muy similar. Elija el que haga que su intención sea más obvia.

CountdownLatch hace que los hilos esperen en el método await (), hasta el momento en que el recuento haya llegado a cero. Entonces, tal vez quieras que todos tus hilos esperen hasta 3 invocaciones de algo, entonces todos los hilos pueden irse. 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 devolverse a un semáforo permitiendo que los otros hilos de espera continúen.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top