并发工具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是一个同步辅助类.允许一个或多个线程等待其他线程 ...
随机推荐
- mysql ORDER BY语句 语法
mysql ORDER BY语句 语法 作用:用于对结果集进行排序. 语法:顺序:SELECT * from 表名 ORDER BY 排序的字段名 倒序:SELECT * from 表名 ORDER ...
- 【bzoj2733】[HNOI2012]永无乡
题目描述: 永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示.某些岛之间由巨大的桥连接,通过桥可以从一个岛 到 ...
- .net api 和java平台对接技术总结
这两天 一直和京东对接接口,我们用.net api 提供接口,对方用java调用,本来没什么问题,但是对方对数据安全要求特别严,要验签,于是噩梦开始了. 1.在传输的时候,约定传输格式: HttpWe ...
- Socket网络通信编程(二)
1.Netty初步 2.HelloWorld 3.Netty核心技术之(TCP拆包和粘包问题) 4.Netty核心技术之(编解码技术) 5.Netty的UDP实现 6.Netty的WebSocket实 ...
- IDEA 创建spring boot 的Hello World 项目
1.Open IDEA,choose "New-->Project" 2.Choose "Spring Initializr" 3. Choose jav ...
- GPG(pgp)加解密中文完整教程
一.介绍 我们都知道,互联网是不安全的,但其上所使用的大部分应用,如Web.Email等一般都只提供明文传输方式(用https.smtps等例外).所以,当我们需要传输重要文件时,应该对当中的信息加密 ...
- Dreamweaver cc新版本css单行显示
新版本通用:(1)C:\Users\admin\Application Data\Adobe\Dreamweaver CC 2018\cloudpref\Adobe Dreamweaver CC 20 ...
- 几种 MyBatis 增强插件
1. mybatis-generator/mybatis-generator-gui 2. 通用mapper 3. mybatis-plus 4. fastmybatis 5. mybatis-enh ...
- PANIC: Missing emulator engine program for ‘x86’ CPU.
参考链接:https://zhidao.baidu.com/question/652153765084187325.html 解决方案:看图最上面路径,进入你的文件夹下,把红文件夹 ( 1 ) 中的所 ...
- Linux_SquidProxyServer代理服务器
目录 目录 Squid proxy server Web proxy server operating principle Squid features Setup squid server Setu ...