CountDownLatch源码分析

基于AQS实现,有关AQS的原理参考juejin.cn/post/748158... ,本文涉及AQS的方法不再重复分析。

构造方法

arduino 复制代码
public CountDownLatch(int count) {
    //参数值校验
    if (count < 0) throw new IllegalArgumentException("count < 0");
    //创建Sync类,继承AQS
    this.sync = new Sync(count);
}
scss 复制代码
Sync(int count) {
    //设置state值
    setState(count);
}

await()

csharp 复制代码
public void await() throws InterruptedException {
    sync.acquireSharedInterruptibly(1);
}
java 复制代码
public final void acquireSharedInterruptibly(int arg)
        throws InterruptedException {
     //中断状态,抛出中断异常   
    if (Thread.interrupted())
        throw new InterruptedException();
    // state等于0说明所有的线程都已经countDown了 
    if (tryAcquireShared(arg) < 0)
        //加入同步队列并阻塞
        doAcquireSharedInterruptibly(arg);
}
arduino 复制代码
protected int tryAcquireShared(int acquires) {
    return (getState() == 0) ? 1 : -1;
}
java 复制代码
private void doAcquireSharedInterruptibly(int arg)
    throws InterruptedException {
    //构建共享模式节点添加到同步队列
    //这里同步队列里就只是一个哨兵节点和一个执行await()线程节点
    final Node node = addWaiter(Node.SHARED);
    boolean failed = true;
    try {
        for (;;) {
            //前驱节点
            final Node p = node.predecessor();
            //是头节点
            if (p == head) {
                //看state是否等于0
                int r = tryAcquireShared(arg);
                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);
    }
}

await()逻辑总结:

  1. 先尝试查看state是不是0,是0说明所有的线程都已经countDown了;
  2. 不是0,说明还有线程没有走完业务逻辑执行countDown操作,把执行await()方法的线程加入到同步队列;
  3. 前驱节点是头节点的话先尝试在看state是否是0,不是的话阻塞线程,等countDown后为0唤醒

countDown()

csharp 复制代码
public void countDown() {
    sync.releaseShared(1);
}
arduino 复制代码
public final boolean releaseShared(int arg) {
    //判断state是否是正常countDown操作减为0
    if (tryReleaseShared(arg)) {
        //唤醒同步队列节点,也就是执行await()的线程
        doReleaseShared();
        return true;
    }
    return false;
}
ini 复制代码
protected boolean tryReleaseShared(int releases) {
    // Decrement count; signal when transition to zero
    for (;;) {
        int c = getState();
        if (c == 0)
            return false;
        //状态减1    
        int nextc = c-1;
        //CAS设置
        if (compareAndSetState(c, nextc))
            //为0成功
            return nextc == 0;
    }
}

countDown()逻辑总结:

  1. 循环减1state直到为0,然后唤醒执行await()的线程
相关推荐
ZGG0031 小时前
线程池详解:从 7 大参数到生产避坑
java·数据库·后端
geovindu2 小时前
CSharp: Wordcloud
开发语言·后端·c#·.net·.netcore·词云
geovindu3 小时前
CSharp: Command Pattern
开发语言·后端·c#·.net·.netcore·命令模式·行为模式
tedcloud1234 小时前
OpenLogi 怎么搭建?用 Rust 打造一个轻量的 Logitech 外设管理工具
linux·运维·服务器·开发语言·后端·rust·开源
学长毕业设计5 小时前
基于SpringBoot的健康食谱管理系统的设计与实现(源码+文档+讲解视频)
java·spring boot·后端
逃逸线LOF5 小时前
Spring的AOP简介
java·后端·spring
yume_sibai6 小时前
02-Rust 所有权与借用深入解析(底层原理 + 借用检查器 + 生命周期 + 内部可变性)
开发语言·后端·rust
卷无止境6 小时前
从脚本到程序:Windows平台上的Python打包全景图
后端·python
骇客野人6 小时前
Springboot 的 配置文件 application.yml 和 bootrap.yml 的由来和作用
java·spring boot·后端
岁月宁静6 小时前
三、《从零手撸 Agent》 · system prompt 与核心参数:调好你的旋钮
后端·python·agent