CountDownLatch 源码分析
CountDownLatch 源码分析:
1:CountDownLatch数据结构
成员变量 Sync类型对象
private final Sync sync; Sync是继承AQS的一个类,CountDownLatch是通过AQS和CAS来实现它的锁的功能的;
2构造方法:
public CountDownLatch(int count) { //需要等待调用countDown() 的次数 这个例子中count=5 来举例说明
if (count < 0) throw new IllegalArgumentException("count < 0");
this.sync = new Sync(count); //创建Sync对象,AQS的子类
}
Sync(int count) {
setState(count); //设置AQS类中state=count=5 state 是volitle修饰的
}
3:await 方法分析:
public void await() throws InterruptedException {
sync.acquireSharedInterruptibly(1); //调用AQS中的acquireSharedInterruptibly方法
}
AQS. acquireSharedInterruptibly() 源码如下:
public final void acquireSharedInterruptibly(int arg) // arg=1
throws InterruptedException {
if (Thread.interrupted()) // 当前线程是否中断状态 如果中断则抛出异常
throw new InterruptedException();
if (tryAcquireShared(arg) < 0) //尝试获取共享锁
doAcquireSharedInterruptibly(arg);
}
tryAcquireShared方法如下:
protected int tryAcquireShared(int acquires) { // acquires=1
return (getState() == 0) ? 1 : -1; //state=5 表明未获取到锁,则返回 -1
}
返回-1后满足tryAcquireShared(arg) < 0这个条件,则进入doAcquireSharedInterruptibly(arg);
这个方法:下面对这个方法分析:
在分析这个源码之前,说明下 for(;;) 的作用:不断的轮询,相当于while(true)
private void doAcquireSharedInterruptibly(int arg) // arg=1
throws InterruptedException {
创建当前线程的节点,并且锁的模型是 共享锁 将其添加到AQS CLH队列的末尾
final Node node = addWaiter(Node.SHARED);
boolean failed = true;
try {
for (;;) { //轮询以下代码的逻辑
final Node p = node.predecessor(); //获取前继节点
if (p == head) { //前继节点是表头则进入以下逻辑
int r = tryAcquireShared(arg); //尝试获取锁 这里state=5 获取锁失败
if (r >= 0) {
setHeadAndPropagate(node, r);
p.next = null; // help GC
failed = false;
return;
}
}
//前继节点不是表头或者获取共享锁失败则进入以下逻辑,当前挂起,一直到获取到共享锁
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt()) //当前线程挂起,一直等待
throw new InterruptedException();
}
} finally {
if (failed)
cancelAcquire(node);
}
}
下面对shouldParkAfterFailedAcquire 这个方法进行分析,这个之前在公平锁中有过分析
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus; //for(;;)第一次进入是waitStatus=0
if (ws == Node.SIGNAL)
return true; //第二次进入的时候返回 true
if (ws > 0) {
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else {
compareAndSetWaitStatus(pred, ws, Node.SIGNAL); //设置waitStatus=-1
}
return false;
}
接下来分析下 countDown方法:
public void countDown() {
sync.releaseShared(1);
}
releaseShared的方法如下: 目的 将AQS中的state -1,当state减到0的时候返回true
public final boolean releaseShared(int arg) { // arg=1
if (tryReleaseShared(arg)) {
doReleaseShared(); //这段代码的作用是unpark 被await 的线程;
具体的实现是:调用后继节点的LockSupport.unpark(s.thread); 这里的s节点就是head节点的后继节点;也就是前面调用await被挂起的线程节点
return true;
}
return false;
}
通过这里的countDown方法,就和之前的await()方法呼应起来了。实现了,某一个线程等待其他线程执行结束后再执行这个线程
CountDownLatch 源码分析的更多相关文章
- Java - "JUC" CountDownLatch源码分析
Java多线程系列--“JUC锁”09之 CountDownLatch原理和示例 CountDownLatch简介 CountDownLatch是一个同步辅助类,在完成一组正在其他线程中执行的操作之前 ...
- concurrent(五)同步辅助器CountDownLatch & 源码分析
参考文档: https://blog.csdn.net/zxdfc/article/details/52752803 简介 CountDownLatch是一个同步辅助类.允许一个或多个线程等待其他线程 ...
- 并发工具CountDownLatch源码分析
CountDownLatch的作用类似于Thread.join()方法,但比join()更加灵活.它可以等待多个线程(取决于实例化时声明的数量)都达到预期状态或者完成工作以后,通知其他正在等待的线程继 ...
- JUC之CountDownLatch源码分析
CountDownLatch是AbstractQueuedSynchronizer中共享锁模式的一个的实现,是一个同步工具类,用来协调多个线程之间的同步.CountDownLatch能够使一个或多个线 ...
- java源码-CountDownLatch源码分析
这次分析CountDownLatch,相信大部分人都用过把! CountDownLatch内部还是Sync对象,还是基础AQS(可见其重要性),首先看一下CountDownLatch初始化,Count ...
- Java并发系列[7]----CountDownLatch源码分析
CountDownLatch(闭锁)是一个很有用的工具类,利用它我们可以拦截一个或多个线程使其在某个条件成熟后再执行.它的内部提供了一个计数器,在构造闭锁时必须指定计数器的初始值,且计数器的初始值必须 ...
- CountDownLatch源码分析
CountDownLatch.Semaphore(信号量)和ReentrantReadWriteLock.ReadLock(读锁)都采用AbstractOwnableSynchronizer共享排队的 ...
- 【JUC】JDK1.8源码分析之CountDownLatch(五)
一.前言 分析完了CyclicBarrier后,下面分析CountDownLatch,CountDownLatch用于同步一个或多个任务,强制他们等待由其他任务执行的一组操作完成.CountDownL ...
- CountDownLatch源码浅析
Cmd Markdown链接 CountDownLatch源码浅析 参考好文: JDK1.8源码分析之CountDownLatch(五) Java并发之CountDownLatch源码分析 Count ...
随机推荐
- 一文让你读懂Synchronized底层实现,秒杀面试官
本文为死磕Synchronized底层实现第三篇文章,内容为轻量级锁实现. 轻量级锁并不复杂,其中很多内容在偏向锁一文中已提及过,与本文内容会有部分重叠. 另外轻量级锁的背景和基本流程在概论中已有讲解 ...
- 小鸟初学Shell编程(一)认识Shell
开篇介绍 Linux里非常的有用的一个功能,这个功能就叫Shell脚本. Shell脚本在我日常开发工作里也占了非常重要的角色,项目中一些简单的工作我们都可以使用Shell脚本来完成,比如定时删除日志 ...
- jQuery AJAX方法详谈
AJAX是与服务器交换数据并更新部分网页的技术,而无需重新加载整个页面. 下表列出了所有jQuery AJAX方法: 方法 描述 $.ajax() 执行异步AJAX请求 $.ajaxPrefilter ...
- Delphi2007 在Win10 下运行报错 Assertion failure
Delphi2007 原来安装在Win7 下 运行正常, 自从升级到Win10 ,新建工程运行然后关闭报错, 报错信息如下: ---------------------------bds.exe - ...
- ios 开发学习步骤
https://developer.apple.com/library/prerelease/ios/referencelibrary/GettingStarted/RoadMapiOSCh/Wher ...
- Phoenix 无法启动报错: java.net.BindException: Address already in use
一.问题描述 i. 登录Ambari发现有一个节点的 Phoenix 无法启动 ii. 在Ambari上点击“Start”,监控 Phoenix 日志文件 iii. Phoenix 日志如下: [ro ...
- java1.8新特性整理(全)
版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/yitian_66/article/deta ...
- python 登录并获取session,使用session新增ecshop的草稿
,"consignee":"冬天","email":"12345@qq.com","address" ...
- shell之seq
seq 用于生成从一个数到另一个数之间的所有整数 seq [选项]... 尾数 seq [选项]... 首数 尾数 seq [选项]... 首数 增量 尾数 例如: 1. -s 指定分隔符,默认分隔 ...
- Ubuntu下apache2安装配置(内含数字证书配置)
Ubuntu下apache2安装配置(内含数字证书配置)安装命令:sudo apt-get updatesudo apt-get install apache2 配置1.查看apache2安装目录命令 ...