CountDownLatch深度剖析
- 场景引入
日常开发中,有个需求,要求主线程开启多个线程去并行执行任务,并且主线程需要等待所有的子线程执行完成后进行汇总。我们很容易找到 jion()方法来实现这个功能

缺点:由于工作中,我们不会直接创建线程,一般都是交给线程池处理,那么我们就没法对线程池里的线程调用join()方法了。
2.需求升级
主线程不必等所有的子线程全部执行完成就可以进行汇总,并且子线程还能执行其他的无关的功能。查阅JUC包,我们发现CountDownLatch、CyclicBarrier、Semaphore均可以实现这个功能。
今天我们主要学习一下CountDownLatch

3. join 和 CountDownLatch比较
- 调用一个子线程的join()方法后,该线程(主线程)会一直被阻塞,直到子线程运行完成。而CountDownLatch使用计数器,在调用countDown()方法递减计数,在计数器为0时,唤醒阻塞的线程,而不必等到子线程执行完成。
- 在使用线程池执行任务时,join()方法不能使用,CountDownLatch的使用更加灵活。
4. 源码走读
public CountDownLatch(int count) {
if (count < 0) throw new IllegalArgumentException("count < 0");
// 底层是AQS,构造函数的入参传递给AQS的state属性
this.sync = new CountDownLatch.Sync(count);
}
// 调用该方法,计数器的值递减,当计数器的值为0则唤醒所有因调用该方法而阻塞的线程,
//否则什么也不做
public void countDown() {
// 委托sync调用AQS的方法
sync.releaseShared(1);
} public final boolean releaseShared(int arg) {
// 调用sync实现的tryReleaseShared方法
if (tryReleaseShared(arg)) {
// AQS的释放资源方法,唤醒由于调用await方法而阻塞的线程,此时阻塞线程往下执行,但是不影响子线程调用countDown方法后面的代码的继续执行
doReleaseShared();
return true;
}
return false;
}
protected boolean tryReleaseShared(int releases) {
// 循环进行cas,直到当前线程成功完成计数器减一并更新到state
for (;;) {
int c = getState();
if (c == 0)
return false;
int nextc = c - 1;
if (compareAndSetState(c, nextc))
return nextc == 0;
}
}
public void await() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
// 判断state是否为0
if (tryAcquireShared(arg) < 0)
// 如果不为0,则将当前线程加入到AQS的队列等待
doAcquireSharedInterruptibly(arg);
}
// 单纯的判断AQS的state是否为0
protected int tryAcquireShared(int acquires) {do
return (getState() == 0) ? 1 : -1;
}
5. 总结
CountDownLatch基于AQS实现(CountDownLatch静态内部类Sync)。使用AQS的状态值state来存放计数器的值。首先在初始化的时候,设置状态值(计数器的值),当多个线程调用countDown()方法时,实际上是对AQS进行原子性递减。当有线程调用await()方法时后,该线程会被放入AQS的阻塞队列等待计数器为0再返回。其他线程调用 countDown 方法让计数器值递减1,当计数器的值变为0时,当前线程还要调用AQS的 doReleaseShared 方法来激活由于调用 await 方法而阻塞的线程。
CountDownLatch深度剖析的更多相关文章
- 《AngularJS深度剖析与最佳实践》简介
由于年末将至,前阵子一直忙于工作的事务,不得已暂停了微信订阅号的更新,我将会在后续的时间里尽快的继续为大家推送更多的博文.毕竟一个人的力量微薄,精力有限,希望大家能理解,仍然能一如既往的关注和支持sh ...
- ASP.NET Core管道深度剖析(2):创建一个“迷你版”的管道来模拟真实管道请求处理流程
从<ASP.NET Core管道深度剖析(1):采用管道处理HTTP请求>我们知道ASP.NET Core请求处理管道由一个服务器和一组有序的中间件组成,所以从总体设计来讲是非常简单的,但 ...
- Objective-C类成员变量深度剖析
目录 Non Fragile ivars 为什么Non Fragile ivars很关键 如何寻址类成员变量 真正的“如何寻址类成员变量” Non Fragile ivars布局调整 为什么Objec ...
- 大众点评开源分布式监控平台 CAT 深度剖析
一.CAT介绍 CAT系统原型和理念来源于eBay的CAL的系统,CAT系统第一代设计者吴其敏在eBay工作长达十几年,对CAL系统有深刻的理解.CAT不仅增强了CAL系统核心模型,还添加了更丰富的报 ...
- 深度剖析WordPress主题结构(转)
利用强大的技术,可以把基于wordpress的网站做成各种各样的形式,这除了要求wordpress主题开发人员精通html,PHP,JS,CSS等技术,还需要开发者掌握WordPress主题的框架. ...
- LCD深度剖析
LCD 深度剖析 来源:http://blog.csdn.net/hardy_2009/article/details/6922900 http://blog.csdn.net/jaylondon/a ...
- WCF技术剖析之十九:深度剖析消息编码(Encoding)实现(下篇)
原文:WCF技术剖析之十九:深度剖析消息编码(Encoding)实现(下篇) [爱心链接:拯救一个25岁身患急性白血病的女孩[内有苏州电视台经济频道<天天山海经>为此录制的节目视频(苏州话 ...
- 大兴雷克萨斯深度剖析2013款LS460L_深圳大兴雷克萨斯_太平洋汽车网
大兴雷克萨斯深度剖析2013款LS460L_深圳大兴雷克萨斯_太平洋汽车网 大兴雷克萨斯深度剖析2013款LS460L
- Java反射机制剖析(四)-深度剖析动态代理原理及总结
动态代理类原理(示例代码参见java反射机制剖析(三)) a) 理解上面的动态代理示例流程 a) 理解上面的动态代理示例流程 b) 代理接口实现类源代码剖析 咱们一起来剖析一下代理实现类($Pr ...
随机推荐
- CoProcessFunction实战三部曲之一:基本功能
欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...
- if判断 和while、for循环
if判断 语法一: if 条件: 条件成立时执行子代码块 代码1 代码2 实例一: sex='female' age=18 is_beautifui=True if sex=='female' ...
- android studio很好用的插件
- 注册dll命令
向系统中注册dll的方法,如下(直接回车即可注册): regsvr32
- 老猿Python博客文章目录索引
本目录提供老猿Python所有相关博文的一级目录汇总,带星号的为收费专栏: 一.专栏列表 本部分为老猿所有专栏的列表,每个专栏都有该专栏置顶的博文目录: 专栏:Python基础教程目录 专栏:* 使用 ...
- 第10.2节 查看导入的Python模块
在Python中,要查看导入模块,可以使用sys.modules来查看,不过sys包含了所有导入模块包括内建模块,如果需要过滤掉内建模块甚至扩展模块,则需要对sys.modules进行一下过滤. 一. ...
- Python特殊序列\d能匹配哪些数字?
在缺省语言环境下,老猿对\d的匹配范围做了个测试,下面的数字包含半角数字.全角数字.中文数字,测试语句如下: >>> m=re.search(r'(\d*)(\D*)(\d*)',' ...
- 十. Axios网络请求封装
1. 网络模块的选择 Vue中发送网络请求有非常多的方式,那么在开发中如何选择呢? 选择一:传统的Ajax是基于XMLHttpRequest(XHR) 为什么不用它呢?非常好解释配置和调用方式等非常混 ...
- Intellij IDEA新导入项目运行出现Error:(60, 47) java: -source 1.5 中不支持 diamond 运算符 (请使用 -source 7 或更高版本以启用 diamond 运算符)
后台窗口报错如下: 问题原因 项目jdk版本配置不正确. 解决方案 ①File ->Project Structure ② ③之后还要检查一下这里 Settings-->Build,Exe ...
- 团队作业4-Day4
团队作业4-Day4 项目git地址 1. 站立式会议 2. 项目燃尽图 3. 适当的项目截图 4. 代码/文档签入记录(部分) 5. 每人每日总结 吴梓华:完成了排位模式与练习模式的界面实现,整合代 ...