[译转]Java CyclicBarrier与CountDownLatch

网友投稿 605 2022-05-28

原文:Java CyclicBarrier与CountDownLatch

[译转]Java CyclicBarrier与CountDownLatch

1.简介

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

2.这些是什么?

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

首先,CountDownLatch和CyclicBarrier都用于管理多线程应用程序。

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

2.1。 CountDownLatch(自减门闩)

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

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

2.2。 CyclicBarrier(循环阻障)

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

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

2.3。进一步阅读

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

3.任务与线程

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

如定义中所述,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());

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

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

但是,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为7的CountDownLatch,并通过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 7的CyclicBarrier 并从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.结论

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

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

其他相关讨论:

Java concurrency: Countdown latch vs Cyclic barrier

CountDownLatch与CyclicBarrier

Java

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:kafka源码解析之三:Log模块读写源码分析——(三)
下一篇:条形压电陶瓷执行器件和高压驱动器
相关文章