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 源码分析的更多相关文章

  1. Java - "JUC" CountDownLatch源码分析

    Java多线程系列--“JUC锁”09之 CountDownLatch原理和示例 CountDownLatch简介 CountDownLatch是一个同步辅助类,在完成一组正在其他线程中执行的操作之前 ...

  2. concurrent(五)同步辅助器CountDownLatch & 源码分析

    参考文档: https://blog.csdn.net/zxdfc/article/details/52752803 简介 CountDownLatch是一个同步辅助类.允许一个或多个线程等待其他线程 ...

  3. 并发工具CountDownLatch源码分析

    CountDownLatch的作用类似于Thread.join()方法,但比join()更加灵活.它可以等待多个线程(取决于实例化时声明的数量)都达到预期状态或者完成工作以后,通知其他正在等待的线程继 ...

  4. JUC之CountDownLatch源码分析

    CountDownLatch是AbstractQueuedSynchronizer中共享锁模式的一个的实现,是一个同步工具类,用来协调多个线程之间的同步.CountDownLatch能够使一个或多个线 ...

  5. java源码-CountDownLatch源码分析

    这次分析CountDownLatch,相信大部分人都用过把! CountDownLatch内部还是Sync对象,还是基础AQS(可见其重要性),首先看一下CountDownLatch初始化,Count ...

  6. Java并发系列[7]----CountDownLatch源码分析

    CountDownLatch(闭锁)是一个很有用的工具类,利用它我们可以拦截一个或多个线程使其在某个条件成熟后再执行.它的内部提供了一个计数器,在构造闭锁时必须指定计数器的初始值,且计数器的初始值必须 ...

  7. CountDownLatch源码分析

    CountDownLatch.Semaphore(信号量)和ReentrantReadWriteLock.ReadLock(读锁)都采用AbstractOwnableSynchronizer共享排队的 ...

  8. 【JUC】JDK1.8源码分析之CountDownLatch(五)

    一.前言 分析完了CyclicBarrier后,下面分析CountDownLatch,CountDownLatch用于同步一个或多个任务,强制他们等待由其他任务执行的一组操作完成.CountDownL ...

  9. CountDownLatch源码浅析

    Cmd Markdown链接 CountDownLatch源码浅析 参考好文: JDK1.8源码分析之CountDownLatch(五) Java并发之CountDownLatch源码分析 Count ...

随机推荐

  1. 你不知道的Golang map

    在开发过程中,map是必不可少的数据结构,在Golang中,使用map或多或少会遇到与其他语言不一样的体验,比如访问不存在的元素会返回其类型的空值.map的大小究竟是多少,为什么会报"can ...

  2. Delphi CreateProcess

    Delphi CreateProcess WIN32API函数CreateProcess用来创建一个新的进程和它的主线程,这个新进程运行指定的可执行文件 2010-12-27 17:00:17|  分 ...

  3. 模拟退火算法SA原理及python、java、php、c++语言代码实现TSP旅行商问题,智能优化算法,随机寻优算法,全局最短路径

    模拟退火算法SA原理及python.java.php.c++语言代码实现TSP旅行商问题,智能优化算法,随机寻优算法,全局最短路径 模拟退火算法(Simulated Annealing,SA)最早的思 ...

  4. UITableView与UITableViewCell

    转自:http://blog.sina.com.cn/s/blog_4cd14afb01014j97.html UITableView用来以表格的形式显示数据.关于UITableView,我们应该注意 ...

  5. vuejs兄弟通信$emit和$on

    1   vm.$on( event, callback ) 监听当前实例上的自定义事件.事件可以由vm.$emit触发.回调函数会接收所有传入事件触发函数的额外参数. 2 vm.$emit( even ...

  6. shuffle调优

    目录 一.概述 二.shuffle的定义 三.ShuffleMananger发展概述 四.HashShuffleManager的运行原理 4.1 未经优化的HashShuffleManager 4.2 ...

  7. MariaDB设置主从复制

    主从复制包含两个步骤: 在 master 主服务器(组)上的设置,以及在 slave 从属服务器(组)上的设置. 配置主服务器 master 如果没有启用,则需要 激活二进制日志. 给 master ...

  8. jenkins自动打包生成docker镜像后自动发布并nginx代理访问

    之前曾写过docker及jenkins基础使用  https://www.cnblogs.com/xiaochangwei/category/816943.html 现在搭建环境的功能为: 1.jen ...

  9. 关于k8s集群证书1年过期后,使用kubadm重新生成证书及kubeconfig配置文件的变化

    这个证书很重要,不用说. 但手工生成证书,确实工作量大且容易出错. 推荐的方式,是保留/etc/kubernetes/pki目录下的ca.crt,ca.key,sa.crt,sa.key. 这四个文件 ...

  10. 通过fiddler抓包,用jmeter实现multipart/form-data类型请求

    Fiddler抓包结果如下: 1.multipart/form-data的基础方式是post,也就是说通过post组合方式来实现的.2.multipart/form-data于post方法的不同之处在 ...