Java CyclicBarrier vs CountDownLatch

Java CyclicBarrier vs CountDownLatch

1. introduction

Dans ce didacticiel, nous compareronsCyclicBarrier etCountDownLatch et essayerons de comprendre les similitudes et les différences entre les deux.

2. Qu'est-ce que c'est?

En matière de simultanéité, il peut être difficile de conceptualiser ce que chacun est censé accomplir.

Tout d'abord, les deuxCountDownLatch and CyclicBarrier are used for managing multi-threaded applications.

Et,they are both intended to express how a given thread or group of threads should wait.

2.1. CountDownLatch

UnCountDownLatch est une construction sur laquelle un threadwaitest activé tandis que d'autres threadscount downont sur le verrou jusqu'à ce qu'il atteigne zéro.

Nous pouvons penser à cela comme un plat dans un restaurant en cours de préparation. Quel que soit le cuisinier qui prépare le nombre de sitems, le serveur doitwait jusqu'à ce que tous les plats soient dans l'assiette. Si une assiette prenditems, n'importe quel cuisinier feracount down on le loquet pour chaque article qu'il met sur l'assiette.

2.2. CyclicBarrier

UnCyclicBarrier  est une construction réutilisable où un groupe de threadswaits ensemble jusqu'à ce que tous les threadsarrive. À ce stade, la barrière est rompue et unaction peut éventuellement être pris.

Nous pouvons penser à cela comme un groupe d'amis. Chaque fois qu'ils envisagent de manger dans un restaurant, ils décident d'un point commun où ils peuvent se rencontrer. Ilswait  l'un pour l'autre là-bas, et seulement quand tout le mondearrives peut aller au restaurant pour manger ensemble.

2.3. Lectures complémentaires

Et pour plus de détails sur chacun d'eux individuellement, reportez-vous à nos précédents tutoriels surCountDownLatch etCyclicBarrier respectivement.

3. Tâches vs Les fils

Examinons plus en détail certaines des différences sémantiques entre ces deux classes.

Comme indiqué dans les définitions,CyclicBarrier permet à un certain nombre de threads de s'attendre les uns sur les autres, tandis queCountDownLatch permet à un ou plusieurs threads d'attendre qu'un certain nombre de tâches se terminent.

En bref,CyclicBarrier maintains a count of threads alors queCountDownLatch maintains a count of tasks.

Dans le code suivant, nous définissons unCountDownLatch avec un nombre de deux. Ensuite, nous appelonscountDown() deux fois à partir d'un seul thread:

CountDownLatch countDownLatch = new CountDownLatch(2);
Thread t = new Thread(() -> {
    countDownLatch.countDown();
    countDownLatch.countDown();
});
t.start();
countDownLatch.await();

assertEquals(0, countDownLatch.getCount());

Une fois que le verrou atteint zéro, l'appel àawait revient.

Notez que dans ce cas,we were able to have the same thread decrease the count twice.

Cependant,CyclicBarrier, est différent sur ce point.

Similaire à l'exemple ci-dessus, nous créons à nouveau unCyclicBarrier, avec un nombre de deux et appelonsawait() dessus, cette fois à partir du même thread:

CyclicBarrier cyclicBarrier = new CyclicBarrier(2);
Thread t = new Thread(() -> {
    try {
        cyclicBarrier.await();
        cyclicBarrier.await();
    } catch (InterruptedException | BrokenBarrierException e) {
        // error handling
    }
});
t.start();

assertEquals(1, cyclicBarrier.getNumberWaiting());
assertFalse(cyclicBarrier.isBroken());

La première différence ici est que les fils qui attendent sont eux-mêmes la barrière.

Deuxièmement, et plus important encore,the second await() is useless. A single thread can’t count down a barrier twice.

En effet, parce quet doitwait pour qu'un autre thread appelleawait() - pour ramener le nombre à deux - le deuxième appel det àawait() w n'est pas réellement être invoqué jusqu'à ce que la barrière soit déjà franchie!

Dans notre test,the barrier hasn’t been crossed because we only have one thread waiting and not the two threads that would be required for the barrier to be tripped. Ceci est également évident à partir de la méthodecyclicBarrier.isBroken(), qui renvoiefalse.

4. Réutilisabilité

La deuxième différence la plus évidente entre ces deux classes est la réutilisabilité. Pour élaborer,when the barrier trips in CyclicBarrier, the count resets to its original value.CountDownLatch is different because the count never resets.

Dans le code donné, nous définissons unCountDownLatch avec le compte 7 et le comptons à travers 20 appels différents:

CountDownLatch countDownLatch = new CountDownLatch(7);
ExecutorService es = Executors.newFixedThreadPool(20);
for (int i = 0; i < 20; i++) {
    es.execute(() -> {
        long prevValue = countDownLatch.getCount();
        countDownLatch.countDown();
        if (countDownLatch.getCount() != prevValue) {
            outputScraper.add("Count Updated");
        }
    });
}
es.shutdown();

assertTrue(outputScraper.size() <= 7);

Nous observons que même si 20 threads différents appellentcountDown(), le compte ne se réinitialise pas une fois qu’il atteint zéro.

Similaire à l'exemple ci-dessus, nous définissons un nombre de swithCyclicBarrier 7 et attendons dessus à partir de 20 threads différents:

CyclicBarrier cyclicBarrier = new CyclicBarrier(7);

ExecutorService es = Executors.newFixedThreadPool(20);
for (int i = 0; i < 20; i++) {
    es.execute(() -> {
        try {
            if (cyclicBarrier.getNumberWaiting() <= 0) {
                outputScraper.add("Count Updated");
            }
            cyclicBarrier.await();
        } catch (InterruptedException | BrokenBarrierException e) {
            // error handling
        }
    });
}
es.shutdown();

assertTrue(outputScraper.size() > 7);

Dans ce cas, nous observons que la valeur diminue chaque fois qu'un nouveau thread s'exécute, en rétablissant sa valeur d'origine, une fois qu'il atteint zéro.

5. Conclusion

Dans l'ensemble,CyclicBarrier etCountDownLatch  sont deux outils utiles pour la synchronisation entre plusieurs threads. Cependant, leurs fonctionnalités sont fondamentalement différentes. Considérez chaque cas avec soin pour déterminer lequel convient le mieux à votre travail.

Comme d'habitude, tous les exemples discutés sont accessiblesover on Github.