2008-10-08 13 views
80

¿Hay alguna ventaja de utilizarCountDownLatch vs Semáforo

java.util.concurrent.CountdownLatch

en lugar de

java.util.concurrent.Semaphore?

Por lo que yo 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(); 

Salvo que en el caso # 2 el pestillo no puede reutilizarse y, lo que es más importante, debe saber con antelación h Se crearán muchos subprocesos (o espere hasta que estén todos iniciados antes de crear el pestillo).

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

Respuesta

92

El seguro CountDown se usa con frecuencia para el opuesto exacto de su ejemplo. Generalmente, tendrías muchos hilos bloqueando en "await()" que todos comenzarían simultáneamente cuando el countown 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 puede utilizar esto como una "barrera" de estilo MPI que hace que todas las discusiones que esperar a que otros hilos para ponerse 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 de cuenta regresiva puede ser utilizado con seguridad en la forma que has demostrado en tu ejemplo.

+0

Gracias. Por lo tanto, mis dos ejemplos no serían equivalentes si varios subprocesos pudieran esperar en el pestillo ... a menos que sem.acquire (num_threads); es seguido por sem.lanzamiento (num_threads) ;? Creo que eso los haría equivalentes de nuevo. – finnw

+0

En cierto sentido, sí, siempre y cuando cada hilo denominado adquirir seguido de lanzamiento. Estrictamente hablando, no. Con un seguro, todos los hilos son elegibles para comenzar simultáneamente. Con el semáforo, se vuelven elegibles uno tras otro (lo que podría dar lugar a una programación diferente del hilo). –

+0

La documentación de Java parece implicar que un CountdownLatch encaja bien con su ejemplo: http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/CountDownLatch.html. Específicamente, "Un CountDownLatch inicializado en N se puede usar para hacer que un hilo espere hasta que N hilos hayan completado alguna acción o alguna acción se haya completado N veces". –

0

CountdownLatch hace que los subprocesos esperen en el método await(), hasta que el recuento llegue a cero. Así que tal vez quieras que todos tus hilos esperen hasta 3 invocaciones de algo, entonces todos los hilos pueden irse. Un pestillo en general no se puede restablecer.

Un semáforo permite que los hilos recuperen permisos, lo que evita que demasiados hilos se ejecuten a la vez, bloqueando si no puede obtener los permisos necesarios para proceder. Los permisos pueden devolverse a un semáforo permitiendo que los otros hilos de espera continúen.

+1

un semáforo hace lo que hace un semáforo. su caso de uso presentado es válido y parece que no hay ninguna diferencia en él countdownlatch vs. semáforo, excepto que puede reutilizar el semáforo. the await es funcionalmente lo mismo que recuperar num_threads cantidad de permisos con .acquire (num_threads); por lo que la única ventaja de la cuenta regresiva parece ser que tiene menos funcionalidad y se agregó más adelante. la ventaja es que no puede restablecerlo aunque lo desee. copiar y pegar las respuestas de los sitios que son sitios de copiado en realidad no ayudan, el análisis detallado de las fuentes de ambos lo haría. –

1

Al mirar la fuente de libre acceso, no hay magia en la implementación de las dos clases, por lo que su rendimiento debería ser muy similar. Elija el que hace que su intención sea más obvia.

59

CountDownLatch se utiliza para iniciar una serie de hilos y luego esperar hasta que todos ellos se han completado (o hasta que ellos llaman countDown() un número determinado de veces.

semáforo se utiliza para controlar el número de subprocesos simultáneos que son utilizando un recurso. Ese recurso puede ser algo así como un archivo, o podría ser la CPU mediante la limitación del número de hilos de ejecución. el recuento en un semáforo puede ir hacia arriba y hacia abajo como diferentes hilos llamar acquire() y release().

en su Por ejemplo, esencialmente está utilizando Semaphore como una especie de Conde UP Pestillo.Dado que su intención es esperar a que finalicen todos los hilos, usar el CountdownLatch aclara su intención.

3

Decir que entré a tienda de golf, con la esperanza de encontrar un conjunto de cuatro,

Cuando se pone de pie en la cola para conseguir una hora de salida de una de las encargadas de tienda pro, en esencia lo que se llama proshopVendorSemaphore.acquire(), una vez que se obtiene una hora del tee, llamó al proshopVendorSemaphore.release(). Nota: cualquiera de los asistentes gratuitos puede darle servicio, es decir, recurso compartido.

Ahora entras al arrancador, inicia un CountDownLatch(4) y llama al await() para esperar a los demás, por tu parte llamaste al check-in, es decir, CountDownLatch. countDown() y también lo hace el resto del cuarteto. Cuando todos llegan, arrancador da luz verde (retornos await() llamadas)

Ahora, después de nueve hoyos cuando cada uno de ustedes a tomar un descanso, hipotéticamente permite involucrar arranque de nuevo, se utiliza un 'nuevo' CountDownLatch(4) dar el primer golpe de hoyo 10, el mismo esperar/sincronizar como Hoyo 1.

Sin embargo, si el motor de arranque usó un CyclicBarrier para empezar, podría haber reiniciado la misma instancia en el Hoyo 10 en lugar de un segundo enganche, que usa & tiro.

+1

No estoy seguro de entender su respuesta, pero si está tratando de describir cómo funcionan CountdownLatch y Semaphore, ese no es el tema de la pregunta. – finnw

+6

Lamentablemente no sé nada sobre el golf. –

+0

, pero las cosas iniciales podrían hacerse tan bien con .acquire (players) y aumentando el recuento de versiones con lanzamiento. parece que el conteo regresivo tiene menos funcionalidad y no es reutilizable. –

10

Breve resumen:

  1. Semaphore y CountDownLatch sirve propósito diferente.

  2. Use Semaphore para controlar el acceso de subprocesos al recurso.

  3. Uso CountDownLatch que esperar a la finalización de todas las discusiones

semáforo definición de javadocs:

Un semáforo mantiene un conjunto de permisos. Cada adquiere() bloques si es necesario hasta que permiso esté disponible, y luego lo toma. Cada versión () agrega un permiso, potencialmente liberando un adquirente bloqueador.

Sin embargo, no se utilizan objetos de permiso reales; el semáforo solo cuenta el número disponible y actúa en consecuencia.

¿Cómo funciona?

Los semáforos se utilizan para controlar el número de hilos concurrentes que utilizan un recurso resource.That puede ser algo así como un conjunto de datos compartidos, o un bloque de código (sección crítica) o cualquier otro archivo.

El recuento en un semáforo puede subir y bajar a medida que diferentes hilos llaman al acquire() y release().Pero en cualquier punto del tiempo, no puede tener más hilos mayores que el contaje del semáforo.

Semáforo Los casos de uso:

  1. Limitar el acceso concurrente en el disco (esto puede matar rendimiento debido a disco competir busca)
  2. la creación del hilo limitante
  3. agrupación de conexiones JDBC/limitación
  4. Disminución de la conexión de red
  5. Limitación de tareas intensas en memoria o CPU

Echa un vistazo a este article para usos de semáforo.

CountDownLatch definición de javadocs:

Una ayuda de sincronización que permite a uno o más hilos que esperar hasta que un conjunto de operaciones que se realiza en otros hilos completa.

¿Cómo funciona?

CountDownLatch obras de tener un contador inicializado con número de hilos, que se decrementa cada vez que un hilo de completar su ejecución. Cuando el conteo llega a cero, significa que todos los hilos han completado su ejecución, y el hilo en espera en el cierre reanuda la ejecución.

CountDownLatch Los casos de uso:

  1. El logro máximo de paralelismo: A veces queremos iniciar una serie de hilos al mismo tiempo para lograr el máximo paralelismo
  2. Espere N hilos a la ultima antes de la ejecución de inicio
  3. Detección de interbloqueo.

Eche un vistazo a este article para entender claramente los conceptos de CountDownLatch.

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

Cuestiones relacionadas