1. 场景引入

    日常开发中,有个需求,要求主线程开启多个线程去并行执行任务,并且主线程需要等待所有的子线程执行完成后进行汇总。我们很容易找到 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深度剖析的更多相关文章

  1. 《AngularJS深度剖析与最佳实践》简介

    由于年末将至,前阵子一直忙于工作的事务,不得已暂停了微信订阅号的更新,我将会在后续的时间里尽快的继续为大家推送更多的博文.毕竟一个人的力量微薄,精力有限,希望大家能理解,仍然能一如既往的关注和支持sh ...

  2. ASP.NET Core管道深度剖析(2):创建一个“迷你版”的管道来模拟真实管道请求处理流程

    从<ASP.NET Core管道深度剖析(1):采用管道处理HTTP请求>我们知道ASP.NET Core请求处理管道由一个服务器和一组有序的中间件组成,所以从总体设计来讲是非常简单的,但 ...

  3. Objective-C类成员变量深度剖析

    目录 Non Fragile ivars 为什么Non Fragile ivars很关键 如何寻址类成员变量 真正的“如何寻址类成员变量” Non Fragile ivars布局调整 为什么Objec ...

  4. 大众点评开源分布式监控平台 CAT 深度剖析

    一.CAT介绍 CAT系统原型和理念来源于eBay的CAL的系统,CAT系统第一代设计者吴其敏在eBay工作长达十几年,对CAL系统有深刻的理解.CAT不仅增强了CAL系统核心模型,还添加了更丰富的报 ...

  5. 深度剖析WordPress主题结构(转)

    利用强大的技术,可以把基于wordpress的网站做成各种各样的形式,这除了要求wordpress主题开发人员精通html,PHP,JS,CSS等技术,还需要开发者掌握WordPress主题的框架. ...

  6. LCD深度剖析

    LCD 深度剖析 来源:http://blog.csdn.net/hardy_2009/article/details/6922900 http://blog.csdn.net/jaylondon/a ...

  7. WCF技术剖析之十九:深度剖析消息编码(Encoding)实现(下篇)

    原文:WCF技术剖析之十九:深度剖析消息编码(Encoding)实现(下篇) [爱心链接:拯救一个25岁身患急性白血病的女孩[内有苏州电视台经济频道<天天山海经>为此录制的节目视频(苏州话 ...

  8. 大兴雷克萨斯深度剖析2013款LS460L_深圳大兴雷克萨斯_太平洋汽车网

    大兴雷克萨斯深度剖析2013款LS460L_深圳大兴雷克萨斯_太平洋汽车网 大兴雷克萨斯深度剖析2013款LS460L

  9. Java反射机制剖析(四)-深度剖析动态代理原理及总结

    动态代理类原理(示例代码参见java反射机制剖析(三)) a)  理解上面的动态代理示例流程 a)  理解上面的动态代理示例流程 b)  代理接口实现类源代码剖析 咱们一起来剖析一下代理实现类($Pr ...

随机推荐

  1. [BUGCASE]层叠上下文和z-index属性使用不当引发的文本被遮挡的问题

    一.问题描述 在一个fixed-data-table(一个React组件)制作的表格中,需要给表头的字段一个提示的特效,所以做了一个提示层 这个提示层被固定(拖动表格的水平滚动条时固定)的表格列遮住 ...

  2. Asp.NetCore之AutoMapper基础篇

    应用场景 现在由于前后端技术的分离,后端程序员在使用ORM框架开发后台API接口的时候,往往会将数据库的"数据模型"直接提供给前端.而大多数时候,可能这些数据并不能够满足前端展示的 ...

  3. redis雪崩,击穿,穿透

    redis穿透 什么是redis穿透? 1.查询一个一定不存在的数据,由于缓存是不命中时被动写的,并且出于容错考虑,如果从存储层查不到数据则不写入缓存 2.这将导致这个不存在的数据每次请求都要到存储层 ...

  4. 第9.6节 Python使用read函数读取文件内容

    一.语法 read(size=-1) read函数实际上在读取文本文件和二进制文件时,调用的是不同类的read,这是因为文本文件和二进制文件打开后返回的文件对象类型不同,同时读取的具体处理机制上也不同 ...

  5. CVE申请+挖掘指南

    CVE的全称是"Common Vulnerabilities and Exposures"翻译成中文就是"公共漏洞和披露" 可以简单理解跟国内CNVD的通用漏洞 ...

  6. CTF写脚本

    今天总结一下CTF如何写脚本快速得分....(比较菜,能力有限,大佬勿喷) 所谓的写脚本得分,就是利用了 python爬虫的思想,如果之前没有听说过的话,可以去爬虫的相关语法.如果是看网上的视频的话, ...

  7. 条件循环语句组成了Python代码的骨架

    条件控制 我们都知道流程图是有多个分支的,程序中也是如此,在Python中是用if语句来判断程序该走哪个分支的.它的执行过程如下: 代码执行过程如下: if if语句的一般形式如下: if condi ...

  8. Javascript的解码/编码api

    1.fromCharCode() 接受一个指定的 Unicode 值,然后返回一个字符串. 语法:String.fromCharCode(numX,numX,...,numX) 详细了解:http:/ ...

  9. jmeter__问题记录,中文乱码问题(json参数化)

    这种情况在jmeter3.0的版本中才会产生,注意:这不是乱码,而是由于3.0中优化body data后,使用默认的字体(Consolas)不支持汉字的显示.这样的情况可以这样调整:进入jmeter. ...

  10. Maven项目中配置jdk版本

    <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> ...