Concurrencia de Java: Cierre de cuenta atrás vs Barrera cíclica


Estaba leyendo a través de la java.útil.API concurrente , y encontró que

  • CountDownLatch: 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.
  • CyclicBarrier: Una ayuda de sincronización que permite a un conjunto de hilos esperar entre sí para alcanzar un punto de barrera común.

Para mí ambos parecen iguales, pero estoy seguro de que hay mucho más.

Por ejemplo, en CoundownLatch, the countdown value could not be reset, that can happen in the case of CyclicBarrier.

¿hay alguna otra diferencia entre los dos?
¿Cuáles son los use cases donde alguien querría restablecer el valor de countdown?

Author: palacsint, 2010-11-12

12 answers

Una diferencia importante es que CyclicBarrier toma una tarea ejecutable (opcional) que se ejecuta una vez que se cumple la condición de barrera común.

También le permite obtener el número de clientes que esperan en la barrera y el número requerido para activar la barrera. Una vez activada, la barrera se restablece y se puede usar de nuevo.

Para casos de uso simples: servicios que comienzan, etc... un CountdownLatch está bien. Un CyclicBarrier es útil para tareas de coordinación más complejas. Un ejemplo de tal cosa sería la computación paralela-donde múltiples subtareas están involucradas en la computación - tipo de MapReduce.

 116
Author: Jon,
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
2010-11-12 20:43:10

Hay otra diferencia.

Cuando se usa un CyclicBarrier, la suposición es que se especifica el número de hilos en espera que activan la barrera. Si especifica 5, debe tener al menos 5 hilos para llamar await().

Cuando se usa un CountDownLatch, se especifica el número de llamadas a countDown() que dará lugar a que se liberen todos los hilos en espera. Esto significa que puedes usar un CountDownLatch con un solo hilo.

"¿Por qué harías eso?", se puede decir. Imagine que usted está utilizando un misteriosa API codificada por otra persona que realiza devoluciones de llamada. Desea que uno de sus hilos espere hasta que se haya llamado a una determinada devolución de llamada varias veces. No tienes idea de qué hilos se llamará a la devolución de llamada. En este caso, un CountDownLatch es perfecto, mientras que no puedo pensar en ninguna manera de implementar esto usando un CyclicBarrier (en realidad, puedo, pero implica tiempos de espera... ¡qué asco!).

Solo deseo que CountDownLatch se pueda reiniciar!

 108
Author: Kim,
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
2011-03-01 04:53:33

Un punto que nadie ha mencionado aún es que, en un CyclicBarrier, si un hilo tiene un problema (tiempo de espera, interrumpido...), todos los demás que han alcanzado await() obtienen una excepción. Véase Javadoc:

El CyclicBarrier utiliza un modelo de rotura todo o nada para los intentos de sincronización fallidos: Si un hilo deja un punto de barrera prematuramente debido a una interrupción, fallo o tiempo de espera, todos los demás hilos que esperan en ese punto de barrera también se irán anormalmente a través de BrokenBarrierException (o Excepción interrumpida si también se interrumpieron aproximadamente al mismo tiempo).

 34
Author: Chirlo,
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
2012-10-07 16:03:02

Creo que el JavaDoc ha explicado las diferencias explícitamente. La mayoría de la gente sabe que CountDownLatch no se puede restablecer, sin embargo, CyclicBarrier puede. Pero esta no es la única diferencia, o el CyclicBarrier podría ser renombrado a ResetbleCountDownLatch. Debemos decir las diferencias desde la perspectiva de sus objetivos, que se describen en JavaDoc

CountDownLatch: Una ayuda de sincronización que permite que uno o más hilos esperen hasta que se realice un conjunto de operaciones en otros hilos completa.

CyclicBarrier: Una ayuda de sincronización que permite a un conjunto de hilos esperar entre sí para alcanzar un punto de barrera común.

En CountDownLatch, hay uno o más hilos, que están esperando que se complete un conjunto de otros hilos. En esta situación, hay dos tipos de hilos, un tipo está esperando, otro tipo está haciendo algo, después de terminar sus tareas, podrían estar esperando o simplemente terminado.

En CyclicBarrier, solo hay un tipo de hilos, están esperando el uno al otro, son iguales.

 19
Author: Justin Civi,
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
2015-04-11 10:02:48

La principal diferencia está documentada directamente en los Javadocs para CountDownLatch. A saber:

Un CountDownLatch se inicializa con un dada la cuenta. El bloque de métodos await hasta que el conteo actual llegue a cero debido a las invocaciones de la cuenta atrás() método, después de lo cual todos esperando hilos se liberan y cualquier invocaciones posteriores de await return inmediatamente. Este es un one-shot fenómeno the el conde no puede ser restablecer. Si necesita una versión que restablece el cuenta, considera usar un CyclicBarrier.

Fuente 1.6 Javadoc

 12
Author: JohnnyO,
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
2010-11-12 20:44:11

Esta pregunta ya ha sido respondida adecuadamente, pero creo que puedo agregar un poco de valor publicando algún código.

Para ilustrar el comportamiento de la barrera cíclica, he hecho un código de ejemplo. Tan pronto como la barrera se inclina, se restablece automáticamente para que pueda usarse de nuevo (por lo tanto, es "cíclica"). Cuando ejecute el programa, observe que las impresiones "Let's play" se activan solo después de que se incline la barrera.

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

public class CyclicBarrierCycles {

    static CyclicBarrier barrier;

    public static void main(String[] args) throws InterruptedException {
        barrier = new CyclicBarrier(3); 

        new Worker().start();
        Thread.sleep(1000);
        new Worker().start();
        Thread.sleep(1000);
        new Worker().start();
        Thread.sleep(1000);

        System.out.println("Barrier automatically resets.");

        new Worker().start();
        Thread.sleep(1000);
        new Worker().start();
        Thread.sleep(1000);
        new Worker().start();
    }

}


class Worker extends Thread {
    @Override
    public void run() {
        try {
            CyclicBarrierCycles.barrier.await();
            System.out.println("Let's play.");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (BrokenBarrierException e) {
            e.printStackTrace();
        }
    }
}
 10
Author: Kevin Lee,
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
2014-04-12 06:24:56

Se utiliza un CountDownLatch para la sincronización de una sola vez. Mientras se usa un CountDownLatch, cualquier hilo puede llamar a countDown () tantas veces como quiera. Los hilos que se llaman await() se bloquean hasta que el conteo llega a cero debido a las llamadas a countDown () por otros hilos desbloqueados. El javadoc para CountDownLatch establece:

Los métodos await bloquean hasta que el conteo actual alcanza cero debido a invocaciones del método countDown (), después de lo cual todo en espera hilo son puestos en libertad y cualquier invocación posterior de await return inmediatamente. ...

Otro uso típico sería dividir un problema en N partes, describir cada parte con un Ejecutable que ejecuta esa parte y cuenta atrás en el latch, y encola todos los Ejecutables a un Ejecutor. Cuando todas las subpartes estén completas, el hilo de coordinación podrá para pasar a través de esperar. (Cuando los hilos deben contar repetidamente hacia abajo en de esta manera, en lugar de CyclicBarrier.)

Por el contrario, la barrera cíclica se usa para múltiples puntos de sincronización, por ejemplo, si un conjunto de hilos está ejecutando un cálculo de bucle/fase y necesita sincronizarse antes de comenzar la siguiente iteración/fase. Según el javadoc para CyclicBarrier :

La barrera se llama cíclica porque se puede reutilizar después de la se liberan los hilos en espera.

A diferencia del CountDownLatch, cada llamada a await() pertenece a alguna fase y puede hacer que el hilo se bloquee hasta que todas las partes pertenecientes a esa fase hayan invocado aawait(). No hay una operación explícita de countDown() soportada por CyclicBarrier.

 9
Author: shams,
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
2012-04-30 02:02:22

En pocas palabras , solo para entender la clave funcional diferencias entre los dos:

public class CountDownLatch {
    private Object mutex = new Object();
    private int count;

    public CountDownLatch(int count) {
        this.count = count;
    }

    public void await() throws InterruptedException {
        synchronized (mutex) {
            while (count > 0) {
                mutex.wait();
            }
        }
    }

    public void countDown() {
        synchronized (mutex) {
            if (--count == 0)
                mutex.notifyAll();
        }

    }
}

Y

public class CyclicBarrier {
    private Object mutex = new Object();
    private int count;

    public CyclicBarrier(int count) {
        this.count = count;
    }

    public void await() throws InterruptedException {
        synchronized (mutex) {
            count--;
            while(count > 0)
                mutex.wait();
            mutex.notifyAll();
        }
    }
}

Excepto, por supuesto, características como no bloqueo, espera temporizada, diagnósticos y todo lo que se ha explicado en detalle en las respuestas anteriores.

Las clases anteriores son, sin embargo, completamente funcionales y equivalentes, dentro de la funcionalidad proporcionada, a sus homónimos correspondientes.

En una nota diferente, la clase interna de CountDownLatch subclases AQS, mientras que CyclicBarrier usa ReentrantLock (mi sospecha es que podría ser al revés o ambos podrían usar AQS o ambos usar Bloqueo without sin ninguna pérdida de eficiencia de rendimiento)

 5
Author: igor.zh,
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
2017-01-23 21:56:55

Cuando estaba estudiando acerca de los Pestillos y las barreras cíclicas, se me ocurrieron estas metáforas. cyclicbarriers: Imagine que una empresa tiene una sala de reuniones. Para comenzar la reunión, un cierto número de asistentes a la reunión tienen que venir a la reunión (para que sea oficial). el siguiente es el código de un asistente normal a una reunión (un empleado)

class MeetingAtendee implements Runnable {

CyclicBarrier myMeetingQuorumBarrier;

public MeetingAtendee(CyclicBarrier myMileStoneBarrier) {
    this.myMeetingQuorumBarrier = myMileStoneBarrier;
}

@Override
public void run() {
    try {
        System.out.println(Thread.currentThread().getName() + " i joined the meeting ...");
        myMeetingQuorumBarrier.await();
        System.out.println(Thread.currentThread().getName()+" finally meeting stared ...");
    } catch (InterruptedException e) {
        e.printStackTrace();
    } catch (BrokenBarrierException e) {
        System.out.println("Meeting canceled! every body dance <by chic band!>");
    }
 }
}

El empleado se une a la reunión, espera a que otros vengan a comenzar la reunión. también se sale si la reunión se cancela :) entonces tenemos EL JEFE cómo dosis no le gusta esperar a que otros aparezcan y si pierde a su paciente, cancela la reunión.

class MeetingAtendeeTheBoss implements Runnable {

CyclicBarrier myMeetingQuorumBarrier;

public MeetingAtendeeTheBoss(CyclicBarrier myMileStoneBarrier) {
    this.myMeetingQuorumBarrier = myMileStoneBarrier;
}

@Override
public void run() {
    try {
        System.out.println(Thread.currentThread().getName() + "I am THE BOSS - i joined the meeting ...");
        //boss dose not like to wait too much!! he/she waits for 2 seconds and we END the meeting
        myMeetingQuorumBarrier.await(1,TimeUnit.SECONDS);
        System.out.println(Thread.currentThread().getName()+" finally meeting stared ...");
    } catch (InterruptedException e) {
        e.printStackTrace();
    } catch (BrokenBarrierException e) {
        System.out.println("what WHO canceled The meeting");
    } catch (TimeoutException e) {
        System.out.println("These employees waste my time!!");
    }
 }
}

En un día normal, el empleado viene a la reunión, espera a que otros se presenten y si algunos asistentes no vienen, ¡tienen que esperar indefinidamente! en alguna reunión especial el jefe viene y no le gusta esperar.(5 personas necesitan comenzar la reunión, pero solo el jefe viene y también un empleado entusiasta) por lo que cancela la reunión (enojado)

CyclicBarrier meetingAtendeeQuorum = new CyclicBarrier(5);
Thread atendeeThread = new Thread(new MeetingAtendee(meetingAtendeeQuorum));
Thread atendeeThreadBoss = new Thread(new MeetingAtendeeTheBoss(meetingAtendeeQuorum));
    atendeeThread.start();
    atendeeThreadBoss.start();

Salida:

//Thread-1I am THE BOSS - i joined the meeting ...
// Thread-0 i joined the meeting ...
// These employees waste my time!!
// Meeting canceled! every body dance <by chic band!>

Hay otro escenario en el que otro hilo externo (un terremoto de la tierra) cancela la reunión (método de restablecimiento de llamada). en este caso, todos los hilos en espera se despiertan por una excepción.

class NaturalDisasters implements Runnable {

CyclicBarrier someStupidMeetingAtendeeQuorum;

public NaturalDisasters(CyclicBarrier someStupidMeetingAtendeeQuorum) {
    this.someStupidMeetingAtendeeQuorum = someStupidMeetingAtendeeQuorum;
}

void earthQuakeHappening(){
    System.out.println("earth quaking.....");
    someStupidMeetingAtendeeQuorum.reset();
}

@Override
public void run() {
    earthQuakeHappening();
 }
}

El código en ejecución dará como resultado una salida divertida:

// Thread-1I am THE BOSS - i joined the meeting ...
// Thread-0 i joined the meeting ...
// earth quaking.....
// what WHO canceled The meeting
// Meeting canceled! every body dance <by chic band!>

También puede agregar una secretaria a la sala de reuniones, si se celebra una reunión, documentará todo, pero no forma parte de la reunión:

class MeetingSecretary implements Runnable {

@Override
public void run() {
        System.out.println("preparing meeting documents");
        System.out.println("taking notes ...");
 }
}

Cierres : si el jefe enojado quiere llevar a cabo una exposición para los clientes de la empresa, todo tiene que estar listo (recursos). proporcionamos una lista de tareas pendientes cada trabajador (Hilo) dosifica su trabajo y revisamos la lista de tareas pendientes (algunos trabajadores pintan, otros preparan el sistema de sonido ...). cuando todos los elementos de la lista de tareas están completos (se proporcionan recursos) podemos abrir las puertas a los clientes.

public class Visitor implements Runnable{

CountDownLatch exhibitonDoorlatch = null;

public Visitor (CountDownLatch latch) {
    exhibitonDoorlatch  = latch;
}

public void run() {
    try {
        exhibitonDoorlatch .await();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    System.out.println("customer visiting exebition");
 }
}

Y los trabajadores cómo están preparando la exposición:

class Worker implements Runnable {

CountDownLatch myTodoItem = null;

public Worker(CountDownLatch latch) {
    this.myTodoItem = latch;
}

public void run() {
        System.out.println("doing my part of job ...");
        System.out.println("My work is done! remove it from todo list");
        myTodoItem.countDown();
 }
}

    CountDownLatch preperationTodoList = new CountDownLatch(3);

    // exhibition preparation workers  
    Worker      electricalWorker      = new Worker(preperationTodoList);
    Worker      paintingWorker      = new Worker(preperationTodoList);

    // Exhibition Visitors 
    ExhibitionVisitor exhibitionVisitorA = new ExhibitionVisitor(preperationTodoList);
    ExhibitionVisitor exhibitionVisitorB = new ExhibitionVisitor(preperationTodoList);
    ExhibitionVisitor exhibitionVisitorC = new ExhibitionVisitor(preperationTodoList);

    new Thread(electricalWorker).start();
    new Thread(paintingWorker).start();

    new Thread(exhibitionVisitorA).start();
    new Thread(exhibitionVisitorB).start();
    new Thread(exhibitionVisitorC).start();
 5
Author: NԀƎ,
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
2017-08-09 11:31:12

En el caso de CyclicBarrier, tan pronto como TODOS los subprocesos secundarios comiencen a llamar a barrier.await (), el Ejecutable se ejecuta en la Barrera. Barrera.esperar en cada hilo hijo tomará diferentes lengh de tiempo para terminar, y todos terminan al mismo tiempo.

 4
Author: Brandon,
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
2011-12-14 15:26:29

Una diferencia obvia es que solo N hilos pueden esperar en un CyclicBarrier de N para ser liberados en un ciclo. Pero un número ilimitado de hilos puede esperar en un CountDownLatch de N. El decremento de la cuenta atrás se puede hacer por un hilo N veces o N hilos una vez cada uno o combinaciones.

 4
Author: Pramma,
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
2015-10-29 17:21:07

En CountDownLatch, los hilos principales esperan que otros hilos completen su ejecución. En CyclicBarrier, los hilos de trabajo esperan unos a otros para completar su ejecución.

No puede reutilizar la misma instancia CountDownLatch una vez que el conteo alcanza a cero y el cierre está abierto, por otro lado CyclicBarrier se puede reutilizar restableciendo la barrera, Una vez que la barrera se rompe.

 1
Author: V Jo,
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-05-14 18:38:13