并发工具CountDownLatch源码分析
CountDownLatch的作用类似于Thread.join()方法,但比join()更加灵活。它可以等待多个线程(取决于实例化时声明的数量)都达到预期状态或者完成工作以后,通知其他正在等待的线程继续执行。简单的说,Thread.join()是等待具体的一个线程执行完毕,CountDownLatch等待多个线程。
如果需要统计4个文件中的内容行数,可以用4个线程分别执行,然后用一个线程等待统计结果,最后执行数据汇总。这样场景就适合使用CountDownLatch。
本篇从CountDownLatch的源码分析它的原理机制。再给出一个简单的使用案例。
首先认识一下CountDownLatch中的内部类:
private static final class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = 4982264981922014374L;
Sync(int count) {
setState(count); // 更新AQS中的state
}
int getCount() {
return getState();
}
protected int tryAcquireShared(int acquires) {
return (getState() == ) ? : -;
}
protected boolean tryReleaseShared(int releases) {
// Decrement count; signal when transition to zero
for (;;) {
int c = getState();
if (c == )
return false;
int nextc = c-;
if (compareAndSetState(c, nextc))
return nextc == ;
}
}
}
其实CountDownLatch的机制和ReentrantLock有点像,都是利用AQS(AbstractQueuedSynchronizer)来实现的。CountDownLatch的内部类Sync继承AQS,重写了tryAcquireShared()方法和tryReleaseShared()方法。这里的重点是CountDownLatch的构造函数需要传入一个int值count,就是等待的线程数。这个count被Sync用来直接更新为AQS中的state。
1、await()等待方法
//CountDownLatch
public void await() throws InterruptedException {
sync.acquireSharedInterruptibly();
}
//AQS
public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
if (tryAcquireShared(arg) < ) // 1
doAcquireSharedInterruptibly(arg); // 2
}
//Sync
protected int tryAcquireShared(int acquires) {
return (getState() == ) ? : -;
}
//AQS
private void doAcquireSharedInterruptibly(int arg)
throws InterruptedException {
final Node node = addWaiter(Node.SHARED);
boolean failed = true;
try {
for (;;) {
final Node p = node.predecessor();
if (p == head) {
int r = tryAcquireShared(arg);
if (r >= ) {
setHeadAndPropagate(node, r);
p.next = null; // help GC
failed = false;
return;
}
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
throw new InterruptedException();
}
} finally {
if (failed)
cancelAcquire(node);
}
}
- 调用AQS中的tryAcquireShared()方法时,Sync重写了tryAcquireShared()方法,获取state,判断state是否为0。
- 如果不为0,调用doAcquireSharedInterruptibly()方法,将线程加入队列,挂起线程。
2、countDown()
public void countDown() {
sync.releaseShared();
}
//AQS
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
doReleaseShared();
return true;
}
return false;
}
//Sync
protected boolean tryReleaseShared(int releases) {
// Decrement count; signal when transition to zero
for (;;) {
int c = getState();
if (c == )
return false;
int nextc = c-;
if (compareAndSetState(c, nextc))
return nextc == ;
}
}
重点也是在于Sync重写的tryReleaseShared()方法。利用CAS算法将state减1。如果state减到0,说明所有工作线程都执行完毕,那么就唤醒等待队列中的线程。
使用示例:
public class CountDownLatchTest {
private static CountDownLatch countDownLatch = new CountDownLatch();
private static ThreadPoolExecutor threadPool = new ThreadPoolExecutor(, ,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(10));
public static void main(String[] args) {
//等待线程
for (int i = ; i < ; i++) {
String threadName = "等待线程 " + i;
threadPool.execute(new Runnable() {
@Override
public void run() {
try {
System.out.println(threadName + " 正在等待...");
//等待
countDownLatch.await();
System.out.println(threadName + " 结束等待...");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
//工作线程
for (int i = ; i < ; i++) {
String threadName = "工作线程 " + i;
threadPool.execute(new Runnable() {
@Override
public void run() {
try {
System.out.println(threadName + " 进入...");
//沉睡1秒
TimeUnit.MILLISECONDS.sleep();
System.out.println(threadName + " 完成...");
//通知
countDownLatch.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
threadPool.shutdown();
}
}
执行结果为:
等待线程 1 正在等待...
等待线程 0 正在等待...
工作线程 2 进入...
工作线程 3 进入...
工作线程 4 进入...
工作线程 3 完成...
工作线程 2 完成...
工作线程 4 完成...
等待线程 0 结束等待...
等待线程 1 结束等待...
从结果也能看到,等待线程先执行,调用countDownLatch.await()方法开始等待。每个工作线程工作完成以后,都调用countDownLatch.countDown()方法,告知自己的任务完成。countDownLatch初始参数为3,所以3个工作线程都告知自己结束以后,等待线程才开始工作。
并发工具CountDownLatch源码分析的更多相关文章
- 并发工具CyclicBarrier源码分析及应用
本文首发于微信公众号[猿灯塔],转载引用请说明出处 今天呢!灯塔君跟大家讲: 并发工具CyclicBarrier源码分析及应用 一.CyclicBarrier简介 1.简介 CyclicBarri ...
- Java - "JUC" CountDownLatch源码分析
Java多线程系列--“JUC锁”09之 CountDownLatch原理和示例 CountDownLatch简介 CountDownLatch是一个同步辅助类,在完成一组正在其他线程中执行的操作之前 ...
- CountDownLatch 源码分析
CountDownLatch 源码分析: 1:CountDownLatch数据结构 成员变量 Sync类型对象 private final Sync sync; Sync是继承AQS的一个类,Coun ...
- [软件测试]网站压测工具Webbench源码分析
一.我与webbench二三事 Webbench是一个在linux下使用的非常简单的网站压测工具.它使用fork()模拟多个客户端同时访问我们设定的URL,测试网站在压力下工作的性能.Webbench ...
- 网站(Web)压测工具Webbench源码分析
一.我与webbench二三事 Webbench是一个在linux下使用的非常简单的网站压测工具.它使用fork()模拟多个客户端同时访问我们设定的URL,测试网站在压力下工作的性能.Webbench ...
- Java并发——结合CountDownLatch源码、Semaphore源码及ReentrantLock源码来看AQS原理
前言: 如果说J.U.C包下的核心是什么?那我想答案只有一个就是AQS.那么AQS是什么呢?接下来让我们一起揭开AQS的神秘面纱 AQS是什么? AQS是AbstractQueuedSynchroni ...
- JUC之CountDownLatch源码分析
CountDownLatch是AbstractQueuedSynchronizer中共享锁模式的一个的实现,是一个同步工具类,用来协调多个线程之间的同步.CountDownLatch能够使一个或多个线 ...
- bootstrap_栅格系统_响应式工具_源码分析
-----------------------------------------------------------------------------margin 为负 使盒子重叠 等高 等高 ...
- concurrent(五)同步辅助器CountDownLatch & 源码分析
参考文档: https://blog.csdn.net/zxdfc/article/details/52752803 简介 CountDownLatch是一个同步辅助类.允许一个或多个线程等待其他线程 ...
随机推荐
- spring 知识结构
- 配置服务器(anaconda + jupyter + R)
总结一下整体的流程: 1. 服务器安装anaconda 首先清华镜像站下载anaconda3. 2. 将下载好的文件用scp命令传入服务器 注意:指定端口用-P命令 p大写 本机地址 用户名@服务器I ...
- 「JOISC 2016 Day 3」回转寿司
https://loj.ac/problem/2736 题解 挺有意思的题. 考虑这种操作不好直接维护,还有时限比较长,所以考虑分块. 考虑一个操作对整个块的影响,无非就是可能把最大的拿走,再把新的元 ...
- 正则表达式小结,数据预处理中常用的shell命令
数据预处理中,这部分命令非常有用. 不需要编写代码,直接通过shell脚本通常就能修改文件格式.有时候sed和awk联合几乎能实现所有功能. 管道命令 | 重定向命令>,2>,>&g ...
- Java数据结构与算法(4):二叉查找树
一.二叉查找树定义 二叉树每个节点都不能有多于两个的儿子.二叉查找树是特殊的二叉树,对于树中的每个节点X,它的左子树中的所有项的值小于X中的项,而它的右子树中所有项的值大于X中的项. 二叉查找树节点的 ...
- Microsoft windows terminal
https://github.com/microsoft/terminal 尝试在windows store中安装,结果everything搜索不到 I tried running WindowsTe ...
- sshd使用
sshd服务 1.sshd介绍 sshd为secure shell的简称:可以通过网络在主机中开机shell的服务 连接方式(在客户端):ssh username@ip #文本模式 ...
- Gradle 编译加速
参考:http://www.jianshu.com/p/200d55b4d40a http://blog.isming.me/2015/03/18/android-build-speed-up/ ht ...
- LinkedHashSet 源码分析
LinkedHashSet 1)底层由 LinkedHashMap 支持的 Set 接口实现,该 Set 中的元素具有可预知的迭代顺序. 创建实例 /** * 构造一个新的空 set,其底层 Link ...
- 职位-CTO:CTO
ylbtech-职位-CTO:CTO 首席技术官是技术资源的行政管理者,英文为Chief Technical Officer或Chief Technology Officer,简称CTO.其职责是制订 ...