CyclicBarrier vs CountDownLatch

CyclicBarrier vs CountDownLatch

1.概述

将比较 CyclicBarrier 和 CountDownLatch,并尝试了解两者之间的异同。

2.这些是什么?

当谈到并发时,概念化每个人打算完成的事情可能具有挑战性。首先,CountDownLatch 和 CyclicBarrier 都用于管理多线程应用程序。而且,它们都旨在表达给定线程或线程组应该如何等待。

2.1. CountDownLatch

CountDownLatch 是一个线程等待而其他线程在闩锁上倒计时直到它达到零的构造。

我们可以把这想象成餐厅正在准备的一道菜。 不管哪位厨师准备了多少n种食物,服务员都必须等到所有的食物都放在盘子上。 如果一个盘子里有 n 件物品,任何厨师都会为她放在盘子上的每件物品倒计时。

2.2. CyclicBarrier

CyclicBarrier 是一种可重用的构造,其中一组线程一起等待,直到所有线程都到达。 此时,屏障被打破,可以选择采取行动。

我们可以把这想象成一群朋友。 每次他们计划在一家餐馆吃饭时,他们都会决定一个共同的见面地点。 他们在那里互相等待,等大家都到齐了,才能一起去餐厅吃饭。

3.Tasks vs Threads

接下来深入地研究这两个类之间的一些语义差异。

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

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

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

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

assertEquals(0, countDownLatch.getCount());

一旦闩锁达到零,对 await 的调用就会返回。

请注意,在这种情况下,可以让同一线程减少两次计数。

然而,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());

这里的第一个区别是等待的线程本身就是屏障。

其次,更重要的是,第二个 await() 没用。 单个线程不能对屏障进行两次倒计时。

4.可重用性

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

 List<String> outputScraper = Lists.newArrayList();
 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();
System.out.println(outputScraper.size());//7

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

与上面的例子类似,定义了一个计数为 7 的 CyclicBarrier,并从 20 个不同的线程等待它:

 List<String> outputScraper = Lists.newArrayList();
 CyclicBarrier cyclicBarrier = new CyclicBarrier(7);

ExecutorService es = Executors.newFixedThreadPool(20);
        for (int i = 0; i < 20; i++) {
            es.execute(() -> {
                try {
                    //为0是  CyclicBarrier 重置了
                    if (cyclicBarrier.getNumberWaiting() <= 0) {
                        outputScraper.add("Count Updated");
                    }
                    cyclicBarrier.await();
                } catch (InterruptedException | BrokenBarrierException e) {
                    // error handling
                }
            });
        }
        es.shutdown();
        System.out.println(outputScraper.size());//1

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

5.总结

总而言之,CyclicBarrier 和 CountDownLatch 都是用于多线程之间同步的有用工具。 但是,它们在提供的功能方面有着根本的不同。 在确定哪个适合工作时,仔细考虑每一个。

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值