Question

Je suis en train de lire à travers le java API .util.concurrent , et a constaté que

  • CountDownLatch:. A l'aide de synchronisation qui permet à un ou plusieurs fils à attendre jusqu'à ce qu'un ensemble d'opérations étant effectuée dans d'autres finalise threads
  • CyclicBarrier: A l'aide de synchronisation qui permet à un ensemble de fils à tous attente pour l'autre pour atteindre un point d'arrêt commun.

Pour moi, à la fois semble égale, mais je suis sûr qu'il ya beaucoup plus à lui.

Par exemple, dans CoundownLatch, the countdown value could not be reset, that can happen in the case of CyclicBarrier.

Y at-il autre différence entre les deux?
Quels sont les use cases où quelqu'un voudrait réinitialiser la valeur du compte à rebours?

Était-ce utile?

La solution

Une différence majeure est que CyclicBarrier prend un (en option) tâche Runnable qui est exécutée une fois la condition de barrière commune est satisfaite.

Il vous permet également d'obtenir le nombre de clients qui attendent à la barrière et le nombre requis pour déclencher la barrière. Une fois déclenché la barrière est remis à zéro et peut être utilisé à nouveau.

Pour les cas simples d'utilisation - le démarrage des services, etc ... un CountDownLatch est très bien. Un CyclicBarrier est utile pour les tâches de coordination plus complexes. Un exemple de chose telle serait calcul parallèle - où plusieurs sous-tâches sont impliqués dans le calcul - un peu comme MapReduce .

Autres conseils

Il y a une autre différence.

Lorsque vous utilisez un CyclicBarrier, l'hypothèse est que vous spécifiez le nombre de threads en attente qui déclenchent la barrière. Si vous spécifiez 5, vous devez avoir au moins 5 fils à l'appel await().

Lorsque vous utilisez un CountDownLatch, vous spécifiez le nombre d'appels à countDown() qui résulteront dans tous les threads en attente d'être libéré. Cela signifie que vous pouvez utiliser un CountDownLatch avec un seul fil.

« Pourquoi voudriez-vous faire cela? », Vous pouvez dire. Imaginez que vous utilisez une API mystérieuse codée par quelqu'un d'autre qui exécute callbacks. Vous voulez un de vos fils d'attendre jusqu'à ce qu'un certain rappel a été appelé plusieurs fois. Vous ne savez pas qui visse le rappel sera appelé. Dans ce cas, un CountDownLatch est parfait, alors que je ne peux pas penser à un moyen de mettre en œuvre cette aide d'un CyclicBarrier (en fait, je peux, mais il implique les délais d'attente ... beurk!).

Je souhaite juste que CountDownLatch pourrait être remis à zéro!

Un point que personne n'a encore mentionné est que, dans un CyclicBarrier, si un thread a un problème (délai d'attente, interrompu ...), tous les autres qui ont atteint await() obtiennent une exception. Voir Javadoc:

  

Le CyclicBarrier utilise un tout ou rien modèle de rupture pour les tentatives de synchronisation a échoué: Si un feuilles de fil un point de barrière prématurément en raison de l'interruption, l'échec ou délai d'attente, tous les autres threads en attente à ce point de barrière laissera également anormalement via BrokenBarrierException (ou InterruptedException si elles aussi ont été interrompus à peu près en même temps).

Je pense que le JavaDoc a expliqué les différences explicitement. La plupart des gens savent que CountDownLatch ne peut cependant être remis à zéro, CyclicBarrier peut. Mais ce n'est pas la seule différence, ou CyclicBarrier pourrait être renommé ResetbleCountDownLatch. Nous devrions dire aux différences du point de vue de leurs objectifs, qui sont décrits dans JavaDoc

CountDownLatch:. A l'aide de synchronisation qui permet à un ou plusieurs fils à attendre jusqu'à ce qu'un ensemble d'opérations étant effectuée dans d'autres finalise threads

CyclicBarrier:. A l'aide de synchronisation qui permet à un ensemble de fils à tous attente pour l'autre pour atteindre un point d'arrêt commun

CountDownLatch, il y a un ou plusieurs fils, qui sont en attente d'un ensemble d'autres fils pour terminer. Dans cette situation, il existe deux types de fils, un type est en attente, un autre type est en train de faire quelque chose, se termine après leurs tâches, ils pourraient être en attente ou tout simplement mis fin.

CyclicBarrier, il n'y a qu'un seul type de fils, qu'ils sont en attente pour l'autre, ils sont égaux.

La principale différence est documenté droit dans les Javadocs pour CountDownLatch. A savoir:

  

A CountDownLatch est initialisé avec un   nombre donné. Le bloc de méthodes Attendre les   jusqu'à ce que le cours de comptage zéro du courant   en raison d'invocations du compte à rebours ()   Procédé, après quoi tout attente   fils sont libérés et toute   invocations ultérieures de retour await   immédiatement. C'est un one-shot   phénomène - le nombre ne peut pas être   réinitialiser. Si vous avez besoin d'une version   remet à zéro le compteur, pensez à utiliser un   CyclicBarrier.

Source 1,6 Javadoc

A CountDownLatch est utilisé pour la synchronisation une fois. Tout en utilisant un CountDownLatch, un thread est autorisé à appeler Countdown () autant de fois qu'ils le souhaitent. Fils qui appelle await () sont bloqués jusqu'à ce que le cours de comptage zéro en raison des appels à Countdown () par d'autres sujets non bloqués. Le

  

Les méthodes jusqu'à ce que le bloc Attendre les tronçons de comptage zéro du courant en raison de   invocations de la méthode COUNTDOWN (), après quoi tous les fils d'attente   sont libérés et les invocations ultérieures de retour await   immédiatement.   ...

     

Une autre utilisation typique serait de diviser un problème en N parties,   décrire chaque partie avec un Runnable qui exécute cette partie et   compte sur le loquet, et la file d'attente toutes les runnables à un exécuteur testamentaire.   Lorsque tous les sous-parties sont complètes, le fil de coordination sera en mesure   pour passer à travers attendent. (Lorsque les threads doivent compter à plusieurs reprises dans   De cette façon, au lieu d'utiliser un CyclicBarrier.)

En revanche, la barrière cyclique est utilisé pour de multiples points de sychronization, par exemple, si un ensemble de fils sont en cours d'exécution d'une boucle / phases de calcul et de nécessité de synchroniser avant de démarrer l'itération suivante / phase. Selon le :

  

La barrière est appelée cyclique car il peut être utilisé après la re-   threads en attente sont libérés.

Contrairement au CountDownLatch, chaque appel à await () appartient à une phase et peut provoquer le fil à bloc jusqu'à ce que toutes les parties appartenant à cette phase invoquez await (). Il n'y a pas d'opération Countdown explicite () pris en charge par le CyclicBarrier.

Cette question a été déjà répondu de manière adéquate, mais je pense que je peux valeur ajouter un peu en affichant un code.

Pour illustrer le comportement de la barrière cyclique, j'ai fait quelques exemples de code. Dès que la barrière est pressenti, il est automatiquement reset afin qu'il puisse être utilisé à nouveau (il est donc « cyclique »). Lorsque vous exécutez le programme, observer que les sorties d'impression « Let s play » sont déclenchées uniquement après la barrière est pressenti.

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();
        }
    }
}

Quand je faisais mes études sur les clenches et cyclicbarriers je suis venu avec cette métaphore. cyclicbarriers : Imaginez une entreprise dispose d'une salle de réunion. Pour commencer la réunion, un certain nombre de participants à la réunion doivent venir à la réunion (pour le rendre officiel). ce qui suit est le code d'un participant à la réunion normale (un employé)

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!>");
    }
 }
}

employé se joint à la réunion, attend que d'autres viennent de commencer la réunion. aussi il se quitte si la réunion est annulée :) alors nous avons la BOSS comment des doses non comme d'attendre pour les autres de se présenter et s'il perd son patient, il annule la réunion.

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!!");
    }
 }
}

Un jour normal, employé venu à la réunion d'attente pour les autres de se présenter et si certains participants n `venir, ils doivent attendre indéfiniment! dans certains réunion spéciale le patron vient et il ne aime pas attendre. (5 personnes doivent commencer la réunion, mais seulement le patron vient et aussi un employé enthousiaste) afin qu'il annule la réunion (en colère)

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

Sortie:

//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!>

Il y a un autre scénario dans lequel un autre thread outsider (un tremblement de terre) annule la réunion (méthode de remise à zéro d'appel). dans ce cas, tous les fils d'attente se réveillées par une exception.

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();
 }
}

le code en cours d'exécution entraînera la production drôle:

// 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!>

Vous pouvez également ajouter un secrétaire à la salle de réunion, si une réunion est tenue, elle documentera tout, mais elle ne fait pas partie de la réunion:

class MeetingSecretary implements Runnable {

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

Verrous : si le patron en colère veut organiser une exposition pour les clients de l'entreprise, tous les besoins de chose pour être prêt (ressources). nous fournissons une liste de tâches chaque travailleur (discussion) dose son travail et nous vérifions la liste de tâches (certains travailleurs faire de la peinture, d'autres préparent son système ...). lorsque tous les éléments à faire la liste sont complets (ressources sont fournies), nous pouvons ouvrir les portes aux clients.

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");
 }
}

Et les travailleurs comment se préparent l'exposition:

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();

En un mot , juste pour comprendre la clé fonction différences entre les deux:

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();
        }

    }
}

et

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();
        }
    }
}

sauf, bien sûr, des fonctionnalités telles que la non-blocage, attente chronométré, le diagnostic et tout ce qui a été expliqué dans les détails les réponses ci-dessus.

Les classes ci-dessus sont toutefois pleinement fonctionnelle et l'équivalent, dans les fonctionnalités fournies, à leurs homonymes correspondants.

Dans un autre, intérieur des sous-classes de la classe de CountDownLatch AQS, tandis que CyclicBarrier utilisations ReentrantLock (je soupçonne qu'il pourrait être inverse ou les deux pourraient utiliser AQS ou les deux d'utiliser le verrouillage - sans perte d'efficacité de la performance)

Dans le cas de CyclicBarrier, dès que tous les threads enfant commence appeler barrier.await (), le Runnable est exécuté dans la barrière. Le barrier.await dans chaque thread enfant prendra différentes lengh de temps à la fin, et ils finissent tous en même temps.

Une différence évidente est que N fils peuvent attendent sur un CyclicBarrier de N être sortie dans un cycle. Mais nombre illimité de fils peut attendre sur un CountDownLatch de N. Le compte à rebours peut être fait décrémentation par un temps de fil N ou N fils une fois chacun ou des combinaisons.

CountDownLatch , fils conducteurs attend d'autres threads pour terminer leur exécution. CyclicBarrier , threads de travail attendent les uns des autres pour compléter leur exécution.

Vous ne pouvez pas réutiliser même CountDownLatch par exemple une fois atteint de comptage à zéro et verrouillage est ouvert, d'autre part CyclicBarrier peut être réutilisé en réinitialisant Barrière, Une fois que la barrière est cassée .

CountDownLatch est un compte à rebours de quoi que ce soit; CyclicBarrier est un compte à rebours pour le fil seulement

supposent il y a 5 threads de travail et un fil de l'expéditeur, et lorsque les travailleurs produisent 100 articles, Shipper les expédier.

Pour CountDownLatch, le compteur peut être sur les travailleurs ou les éléments

Pour CyclicBarrier, le compteur peut seulement sur les travailleurs

Si un travailleur tombe sommeil infini, avec CountDownLatch sur les articles, Expéditeur peut expédier; Cependant, avec CyclicBarrier, Expéditeur ne peut jamais être appelé

et Lee @ Kevin @ Jon j'ai essayé CyclicBarrier avec option Runnable. On dirait qu'il fonctionne au début et après la CyclicBarrier est pressenti. Voici le code et la sortie

barrière CyclicBarrier statique;

    public static void main(String[] args) throws InterruptedException {
        barrier = new CyclicBarrier(3, new Runnable() {
            @Override
            public void run() {
                System.out.println("I run in the beginning and after the CyclicBarrier is tipped");
            }
        });

        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();
    }

Sortie

I run in the beginning and after the CyclicBarrier is tipped
Let's play.
Let's play.
Let's play.
Barrier automatically resets.
I run in the beginning and after the CyclicBarrier is tipped
Let's play.
Let's play.
Let's play.
scroll top