JUC并发工具包之CyclicBarrier & CountDownLatch的异同
1、介绍
本文我们将比较一下CyclicBarrier
和CountDownLatch
并了解两者的相似与不同。
2、两者是什么
当谈到并发,将这两者概念化的去解释两者是做什么的,这其实是一件很有挑战的事情。
- 首先,这两者都是管理多线程的工具。
- 其次,两者都具备让一个或多个线程等待执行的功能。
2.1、CountDownLatch
CountDownLatch可以使一个线程阻塞等待其它多个线程执行到countDown方法处,直到最后的count属性递减为0。
我们可以把这想象成餐馆中待上菜的餐盘(西餐中的餐盘,牛肉,蔬菜,水果,各种点缀),不论厨师在这盘菜中准备多少种食材,服务员都得等到所有的食材都准备好才可以端出去。厨师每准备好一个食材,相当于调用一次countDown()方法。
2.2、CyclicBarrier
CyclicBarrier是一个可重复使用对象,当一组线程都在阻塞等待直到所有线程都到达了某一执行点,这时候barrier会置内部属性broken为true表示执行点后面的逻辑可以执行了。
我们可以把这个理解成一群小伙伴准备去餐馆吃饭,两者约定好了一个时间在哪碰面,两者需等待所有人都到了以后才能一起进入餐馆吃饭。
2.3、进一步阅读
想了解这两者各自的细节,可以看下之前写的两篇文章CountDownLatch & CyclicBarrier
3、任务 vs. 线程
我们来深入看看这两者语义上的区别。
正如一开始定义所说的,CyclicBarrier允许多个线程互相等待,然而CountDownLatch允许一个或多个线程去等待多个任务执行完成。
简而言之,CyclicBarrier管理者一组线程,CountDownLatch管理一组任务
下面的代码中,我们定义了一个count为2的CountDownLatch,接下来我们从单个线程中调用countDown()
两次:
CountDownLatch countDownLatch = new CountDownLatch(2);
Thread t = new Thread(() -> {
countDownLatch.countDown();
countDownLatch.countDown();
});
t.start();
countDownLatch.await();
assertEquals(0, countDownLatch.getCount());
一旦CountDownLatch递减到0,外部的await()方法阻塞结束。
请注意这种情况下,我们可以让单个线程递减两次,但是CyclicBarrier在这点上却不可以。
与上面的例子类似,我们又一次创建了parties为2的CyclicBarrier,并在单个线程中调用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()根本就没有用,单线程不能countDown()两次。
确实,线程t必须等待其它线程调用await(),从而让内部的count值变为2,线程t的第二次调用await()不会被执行除非barrier的broken值早已为true了。
在我们的测试中,barrier没有被执行到底是因为我们只创建了一个线程在阻塞,要是有两个线程就会满足barrier被tripped(源码中的术语,表示所有线程都到达执行点)的条件了。,从cyclicBarrier.isBroken()
方法返回false来看这一点很明显了。
4、可重用性
第二个很明显的区别就是可重用性了,我们来解释一下,当barrier在程序中trip了之后,count值会重置为初始值,也就是parties的值。CountDownLatch和它不同是因为它不会重置属性。
下面的代码中我们我们定义了count为7的CountDownLatch,让countDown()方法被调用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()方法,count值一旦到达0之后就不会被重置了。
和上面的例子类似,我们定义一个parties为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);
在这个场景中,我们可以看到线程每调用一次barrier的值都是递减一次,当递减到0的时候就会重置到初始值了。
5、总结
总而言之,两者在多线程的同步问题上都是很有用的工具。就两者提供的功能而言,两者从根本上就不一样。当你要把两者应用到你的工作中去的时候要仔细考量一下。
最后还是一样,代码在这里
JUC并发工具包之CyclicBarrier & CountDownLatch的异同的更多相关文章
- JUC并发工具包之CyclicBarrier
1.简介 CyclicBarrier是一个同步器,允许多个线程等待彼此直到达一个执行点(barrier). CyclicBarrier都是在多个线程必须等到彼此都到达同一个执行点后才执行一段逻辑时才被 ...
- JUC并发工具包之CountDownLatch
1.介绍 本文将介绍CountDownLatch并给出实践中的几个例子,通过使用CountDownLatch我们可以让一个线程阻塞直到其他一个或多个线程执行完成. A synchronization ...
- JUC并发工具类之 CountDownLatch等待多线程完成
上篇JUC同步工具之Semaphore - 池塘里洗澡的鸭子 - 博客园 (cnblogs.com)示例中,资源释放一个线程就可以退出然后另一个线程可以使用了,那如果需要所有规定数量的资源同时释放了才 ...
- juc并发工具类之CountDownLatch闭锁
import java.util.concurrent.CountDownLatch; /** * 闭锁: 在进行某些运算时, 只有其他所有线程的运算全部完成,当前运算才继续执行(程序流中加了一道栅栏 ...
- JUC并发工具包之Semaphore
目录 Semaphore (JDK) Timed Semaphore (Apache Commons) Semaphore vs. Mutex CodeRepo Semaphore (JDK) 我们使 ...
- Java中的并发工具类:CountDownLatch、CyclicBarrier和Semaphore
在java 1.5中,提供了一些非常有用的辅助类来帮助我们进行并发编程,比如CountDownLatch,CyclicBarrier和Semaphore,今天我们就来学习一下这三个辅助类的用法. 一. ...
- 多线程进阶——JUC并发编程之CountDownLatch源码一探究竟
1.学习切入点 JDK的并发包中提供了几个非常有用的并发工具类. CountDownLatch. CyclicBarrier和 Semaphore工具类提供了一种并发流程控制的手段.本文将介绍Coun ...
- 并发工具类:CountDownLatch、CyclicBarrier、Semaphore
在多线程的场景下,有些并发流程需要人为来控制,在JDK的并发包里提供了几个并发工具类:CountDownLatch.CyclicBarrier.Semaphore. 一.CountDownLatch ...
- 并发编程 04——闭锁CountDownLatch 与 栅栏CyclicBarrier
Java并发编程实践 目录 并发编程 01—— ThreadLocal 并发编程 02—— ConcurrentHashMap 并发编程 03—— 阻塞队列和生产者-消费者模式 并发编程 04—— 闭 ...
随机推荐
- centos7下SVN服务器搭建
1,安装 yum install subversion 2,输入rpm -ql subversion查看安装位置 3,创建svn版本库目录 mkdir -p /var/svn/svnrepos 4,创 ...
- oVirt4.4虚拟机备份方法
红帽oVirt于今年推出了oVirt 4.4,该版本在系统.存储.网络.用户界面等方面做出增强功能与优化更新,为oVirt用户提供功能更强大.更灵活的IT基础架构.云祺科技也于最近发布了全新版本云祺容 ...
- 通过两行代码即可调整苹果电脑 Launchpad 图标大小
之前用 13 寸 Mac 的时候我还没觉得,后来换了 16 寸就发现有点不对劲了.因为 Mac 的高分辨率,当你进入 Launchpad 界面,应用图标的大小可能会让你怀疑:这特么是苹果的设计吗?有点 ...
- vue-router入门随笔
下面整理根据官方文档以及自我理解整理,如有不足,请指教. 下面是来自一段官方的原话. Vue Router 是 Vue.js 官方的路由管理器.它和 Vue.js 的核心深度集成,让构建单页面应用变得 ...
- spring基础学习
ClassXmlAplicationContext和FileSystemXmlApplicationContext的区别 https://www.cnblogs.com/sxdcgaq808 ...
- struts2学习总结
https://www.cnblogs.com/wkrbky/p/5891237.html https://www.cnblogs.com/printN/p/6434526.html https:// ...
- 【总结】vertica数据库
1.简介 Vertica是一款基于列式存储架构的数据库,可以支持存放多至PB级别的结构化数据 2.列式存储 行式存储就是以行为单位进行存储,再配合B+树作为索引,就能快速通过主键找到相应的行数据.即大 ...
- spark求相同key的最大值
需求: 求相同key的最大值 [("a", 3), ("a", 2), ("a", 5), ("b", 5), ...
- [Luogu P4178]Tree (点分治+splay)
题面 传送门:https://www.luogu.org/problemnew/show/P4178 Solution 首先,长成这样的题目一定是淀粉质跑不掉了. 考虑到我们不知道K的大小,我们可以开 ...
- #10053 L 语言
L 语言 dalao 看来是水题?我可不这么认为. 很多人都写了我认为不怎么正确的贪心,那就是直接看到一个单词就减去. 那么这组数据就可以 hack 掉了: 2 1 whatis what whati ...