[译转]Java CyclicBarrier与CountDownLatch

举报
Amrf 发表于 2020/10/28 14:20:53 2020/10/28
【摘要】 原文:Java CyclicBarrier与CountDownLatch1.简介在本教程中,我们将比较 CyclicBarrier 和 CountDownLatch并尝试了解两者之间的异同。2.这些是什么?当涉及到并发时,将每个对象要完成的概念概念化可能是一个挑战。首先,CountDownLatch和CyclicBarrier都用于管理多线程应用程序。而且,它们都旨在表示给定线程或线程组应如...

原文:Java CyclicBarrier与CountDownLatch

1.简介

在本教程中,我们将比较 CyclicBarrier 和 CountDownLatch并尝试了解两者之间的异同。

2.这些是什么?

当涉及到并发时,将每个对象要完成的概念概念化可能是一个挑战。


首先,CountDownLatchCyclicBarrier都用于管理多线程应用程序

而且,它们都旨在表示给定线程或线程组应如何等待。

2.1。 CountDownLatch(自减门

一个 CountDownLatch 是一个结构,一个线程等待其他线程 倒计时门闩直至为零。

我们可以将其想象为正在准备的餐厅的一道菜。无论由哪个厨师准备 n种 食物,服务员都必须等到所有食物都放在盘子上。如果一个盘子可 容纳n个 物品,那么任何厨师都会 在他放在盘子上的一个物品的同时对倒计时门闩减一操作

2.2。 CyclicBarrier(循环阻障)

甲 的CyclicBarrier 是可重复使用的构建体,其中一组线程等待在一起,直到所有线程 到达在这一点上,所述屏障破裂,一个 动作可任选地服用。

我们可以将其视为一群朋友。每当他们计划在餐厅用餐时,他们都会决定可以见面的共同点。他们在那儿等着 ,只有每个人到了,他们才能一起去餐厅吃饭。

2.3。进一步阅读

有关每个单独组件的更多详细信息,请分别参考我们之前关于CountDownLatch 和CyclicBarrier的教程  。

3.任务与线程

让我们更深入地研究这两个类之间的一些语义差异。

如定义中所述,CyclicBarrier允许多个线程互相等待,而CountDownLatch允许一个或多个线程等待许多任务完成。

简而言之,CyclicBarrier维护线程CountDownLatch维护任务数

在下面的代码中,我们定义了一个计数为2CountDownLatch接下来,我们从单个线程两次调用 countDown()

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

assertEquals(0, countDownLatch.getCount());

一旦锁存器达到零,等待 调用就会返回。

请注意,在这种情况下,我们能够使同一线程将计数减少两次。

但是,CyclicBarrier在这一点上有所不同。

与上面的示例类似,我们创建一个CyclicBarrier,它的计数再次为2,并在同一线程上调用await()两次

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

这里的第一个区别是正在等待的线程就是barrier(障碍)本身

其次,更重要的是,第二个await() 是无用的单个线程无法对Barrier(障碍)做两次自减

确实,因为 t必须 等待另一个线程调用 await() 才能使计数增加到2,所以t的第二次对await()的 调用实际上不会被调用,直到屏障已经被打破!

在我们的测试中,没有越过障碍,因为我们只有一个线程在等待,而没有两个线程将使障碍被触发。CyclicBarrier.isBroken()方法也很明显,该方法返回false

4.可重用性

这两个类别之间第二个最明显的区别是可重用性。详细地说,当屏障在CyclicBarrier中跳闸时 ,计数将重置为其原始值。 CountDownLatch是不同的,因为计数永远不会重置。

在给定的代码中,我们定义了一个CountCount为7CountDownLatch,并通过20个不同的调用对其进行计数:

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

我们观察到,即使有20个不同的线程调用 countDown(),计数一旦达到零也不会重置。

与上面的示例类似,我们定义一个Countic 7CyclicBarrier 并从20个不同的线程中等待它:

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

在这种情况下,我们观察到每次运行新线程时该值都会减小,一旦达到零,就会重置为原始值。

5.结论

总而言之,  CyclicBarrierCountDownLatch 都是在多个线程之间进行同步的有用工具。但是,它们在功能上根本不同。在确定最适合该工作时,请仔细考虑每个因素。

像往常一样,所有讨论的示例都可以在Github上访问


其他相关讨论:

Java concurrency: Countdown latch vs Cyclic barrier


CountDownLatch与CyclicBarrier


【版权声明】本文为华为云社区用户翻译文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容, 举报邮箱:cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。