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()的线程
相关推荐
JustHappy8 小时前
古法编程秘籍(七):互联网到底是什么?把两台电脑怎么说话搞懂就够了
前端·后端·网络协议
Hommy888 小时前
【剪映小助手】添加图片接口(Add Images)
后端·github·剪映小助手·视频剪辑自动化
GetcharZp8 小时前
别再盲目用 OpenCV 读图了,这才是 CV 预处理的终极杀手锏!
后端
IT_陈寒12 小时前
Vite热更新失效?可能你在用Windows
前端·人工智能·后端
椰椰椰耶13 小时前
[SpringCloud][14]OpenFeign参数传递方法
后端·spring·spring cloud
onething36513 小时前
Spring Boot + Spring AI 从入门到实战:7天转型计划 Day 3 —— 消息表设计 + 级联删除 + 事务管理
人工智能·后端
荣江14 小时前
Hermes Agent 代码仓库打包工具使用指南(repomix-rs 高性能版)
后端
王某某人14 小时前
LangChain4j 入门:Java 程序员的第一个 AI 对话程序
人工智能·后端
码农刚子14 小时前
从零开始:在 Windows 服务器上部署 Node.js 项目(小白实战教程)
后端·node.js
Cache技术分享14 小时前
435. Java 日期时间 API - Clock 灵活获取当前时间
前端·后端