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. Java基础教程——Stream

    Stream流 Java 8 API添加了一种新的机制--Stream(流).Stream和IO流不是一回事. 流式思想:像生产流水线一样,一个操作接一个操作. 使用Stream流的步骤:数据源→转换 ...

  2. JQuery案例:购物车编辑

    购物车编辑 实现了:商品的加减,总价的变动 实现了:全选/全不选(使用prop而不是attr) 实现了:删除(遮罩层) <html> <head> <meta chars ...

  3. 冲刺随笔——Day_One

    这个作业属于哪个课程 软件工程 (福州大学至诚学院 - 计算机工程系) 这个作业要求在哪里 团队作业第五次--Alpha冲刺 这个作业的目标 团队进行Alpha冲刺 作业正文 正文 其他参考文献 无 ...

  4. Spark存储Parquet数据到Hive,对map、array、struct字段类型的处理

    利用Spark往Hive中存储parquet数据,针对一些复杂数据类型如map.array.struct的处理遇到的问题? 为了更好的说明导致问题的原因.现象以及解决方案,首先看下述示例: -- 创建 ...

  5. html基础标签用法

    head title 行级双 网页标题标签 meta 单 存放网页重要信息,字符集,搜索索引,简介等(不显示) a 标签行内双标签 href="跳转路径", (JavaScript ...

  6. PyQt(Python+Qt)学习随笔:QScrollArea为什么不起作用未出现滚动条?

    老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 老猿在进行Scroll Area部件测试时,在下面的窗体中放置了一个Scroll Area部件,在部 ...

  7. 【开发工具】 使用阿里的 Teambition 跟踪BUG修复及需求管理

    刚入公司几个月,公司新项目一直没有用协作工具进行BUG管理,公司也没有专业的测试工程师. 第一阶段开发到了尾声,工作效率实在太低,随决定使用一个比较现代一点的管理工具. 在众多在线项目协作软件中,我选 ...

  8. python接口测试自动化框架-发送邮件,邮箱报错: 535 Error, authentication failed

    1.无意中把腾讯企业邮箱设置为安全登录,接口测试自动化发送邮件,不能被正常接收.错误信息为:535 Error, authentication failed. 原因:认证安全登录后,原来新的邮箱代码传 ...

  9. SQL Server 批量插入数据方案 SqlBulkCopy 的简单封装,让批量插入更方便

    一.Sql Server插入方案介绍 关于 SqlServer 批量插入的方式,有三种比较常用的插入方式,Insert.BatchInsert.SqlBulkCopy,下面我们对比以下三种方案的速度 ...

  10. MySQL技术内幕InnoDB存储引擎(一)——MySQL体系结构和存储引擎

    1.数据库和实例 数据库(database)和实例(instance)不能混淆. 什么是数据库 数据库是物理操作系统文件或其他文件类型的集合.说白了,就是存储着的文件,不会运行起来,只能被实例增删改查 ...