CountDownLatch原理简介和使用过程

前言

本文介绍下面试的高能考点 countDownLatch 的原理和应用

countDownLatch具有的功能

  • CountDownLatch主要有两个方法,当一个或多个线程调用await方法时,这些线程会阻塞。

  • 其它线程调用countDown方法会将计数器减1(调用countDown方法的线程不会阻塞)

  • 当计数器的值变为0时,因await方法阻塞的线程会被唤醒,继续执行。

应用场景

典型的应用场景

如并行计算,当某个处理的运算量很大时,可以将该运算任务拆分成多个子任务,等待所有的子任务都完成之后,父任务再拿到所有子任务的运算结果进行汇总。

原理简介

上图解释

  • TA线程 实例化 CountDownLatch对象并初始count为3
  • TA调用await 使得当前线程等待count为0 类似于看视屏的时候按了暂停键
  • 另外一个T1线程调用了该CountDownLatch对象的countDown方法 使得count变为2
  • T2线程使得count变为1
  • T3线程使得count变为0
  • 此时就会唤醒处于“暂停”状态的TA线程让其继续往下执行

进一步说明

  • CountDownLatch是一个计数器闭锁,通过它可以完成类似于阻塞当前线程的功能,即:一个线程或多个线程一直等待,直到其他线程执行的操作完成。

  • CountDownLatch用一个给定的计数器来初始化,该计数器的操作是原子操作,即同时只能有一个线程去操作该计数器。

  • 调用该类await方法的线程会一直处于阻塞状态,直到其他线程调用countDown方法使当前计数器的值变为零,每次调用countDown计数器的值减1。

  • 当计数器值减至零时,所有因调用await()方法而处于等待状态的线程就会继续往下执行。

  • 这种现象只会出现一次,因为计数器不能被重置,如果业务上需要一个可以重置计数次数的版本,可以考虑使用CycliBarrier

DEMO代码分析

这个示例包含了 线程池和CountDownLatch 的内容 ,更加符合实际使用场景

详细说明上述示例

针对CountDownLatch的说明
  • 初始化一个CountDownLatch 初始值count=5

  • 调用countDownLatch方法 count+-1即 count=count-1 每次调用count值都会减少1个

  • 调用await方法 就是让初始化CountDownLatch的线程等待count值变为0 然后才会继续执行下面的内容

结合线程池对CountDownDatch的说明
  • 主线程创建了一个count为5的CountDownLatch

  • 主线程创建了一个线程池 里面有5个核心线程

  • 往线程池中提交了5个线程并且传入countDownLatch对象到子线程中去

  • 每一个子线程执行时会调用countDown方法将count减1

  • 主线程调用await 等待count变为0

  • count变为0 主线程将继续执行

源码分析

java.util.concurrent.CountDownLatch

分析源码的过程中大家把关注点放在我截图上圈红的地方 然后咱们慢慢的一点一点的把源码看完
这里将count值设置给state变量 调用了AQS类中setState方法
这个变量被volatile修饰
保证了这个变量 具有
1、可见性
2、有序性 防止指令重排序
3、原子性

这里先简单介绍下可见性

上图解释

  • 每一个线程都会有一个本地内存 比如图中线程A有本地内存A 该内存中保留了一份主内存中共享变量的副本

  • 线程A对本地内存A中的共享变量的副本修改了之后 然后会立刻同步刷新到主内存中

  • 并且会让强制缓存了该变量的线程中的数据清空

  • 必须从主内存中重新读取最新的数据

接着说CountDownLatch源码分析
在初始化CountDownLatch的时候会实例化这个继承了AQS的内部类Sync并且将count传给AQS的state变量
countDownLatch的await方法 调用了 AQS的acquireSharedInterruptibly方法并且传入了参数1 接下来对该方法分析
『tryAcquireShared』
在共享模式下尝试获取。这个方法需要查询是否对象的状态允许在共享模式下被获取,如果允许则去获取它。
这个方法总是被线程执行获取共享锁时被调用。如果这个方法报告失败,那么获取方法可能会使线程排队等待,如果它(即,线程)还没入队的话,直到其他的线程发出释放的信号。
默认实现抛出一个“UnsupportedOperationException”
返回:
a)< 0 : 一个负数的返回表示失败;
b) 0 : 0表示在共享模式下获取锁成功,但是后续的获取共享锁将不会成功
c)> 0 : 大于0表示共享模式下获取锁成功,并且后续的获取共享锁可能也会成功,在这种情况下后续等待的线程必须检查是否有效。


看下AQS的子类Sync的tryAcquireShared方法的实现

这个逻辑过程中使用了大量的CAS来进行原子性的修改,当修改失败的时候,是会通过for(;;)来重新循环的,也就是说『doAcquireSharedInterruptibly』使用自旋锁(自旋+CAS)来保证在多线程并发的情况下,队列节点状态也是正确的以及在等待队列的正确性,最终使得当前节点要么获取共享锁成功,要么被挂起等待唤醒

我们需要一个通知信号,主要是因为当前线程要被挂起了(park)。
而如果waitStatus已经是’SIGNAL’的话就无需修改,直接挂起就好,
而如果waitStatus是’CANCELLED’的话,说明prev已经被取消了,是个无效节点了,那么无需修改这个无效节点的waitStatus,而是需要先找到一个有效的prev。
因此,剩下的情况就只有当waitStatus为’0’和’PROPAGAET’了(注意,waitStatus为’CONDITION’是节点不在等待队列中,所以当下情况waitStatus不可能为’CONDITION’),这时我们需要将prev的waitStatus使用CAS的方式修改为’SIGNAL’,而且只有修改成功的情况下,当前的线程才能安全被挂起。
还值得注意的时,因此该方法的CAS操作都是没有自旋的,所以当它操作完CAS后都会返回false,在外层的方法中会使用自旋,当发现返回的是false时,会再次调用该方法,以检查保证有当前node有一个有效的prev,并且其waitStatus为’SIGNAL’,在此情况下当前的线程才会被挂起(park)。
双向链表数据结构
源码分析未完待续 下篇文章继续分析

DEMO代码链接

https://gitee.com/pingfanrenbiji/myconcurrent/tree/master/src/main/java/pers/hanchao/concurrent/eg14

参考文章

https://www.jianshu.com/p/9ee0194d598c
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,045评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,114评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,120评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,902评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,828评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,132评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,590评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,258评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,408评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,335评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,385评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,068评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,660评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,747评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,967评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,406评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,970评论 2 341