1.什么是CountDownLatch
顾名思义,CountDownLatch是一个倒计时器。
适用于 多线程 中,一个线程需要等待其他线程到达指定状态后再继续执行。
举个场景例子,火箭发射。需要3个步骤
1.设定倒计时的时间
2.等待倒计时完成
3.发射
我们用代码来实现一下这个功能
执行结果
2.CountDownLatch的使用方法
就如同举的场景示例一样,CountDownLatch的使用方式也是分3个步骤
1. 实例化 一个CountDownLatch,并且设置计数
2.进行倒计时的线程,在到达指定状态的时候,调用实例的countdown方法,进行倒计数
3.需要等待的线程调用CountDownLatch实例的await方法,当计数归0时继续执行后续动作
3.源码分析
同样是按照步骤来看
1. 构造函数
如上图所示,CountDownLatch中有个内部类Sync继承了aqs。CountDownLatch只有一个带count的构造函数,这个count是用于初始化aqs的state,且该state是violate的(关于violate可以参考这篇文章 ),因此可以保证多线程环境下的可见。
2.await方法
await是最核心也是最重的方法。
可以看到await方法是调用的sync的acquireSharedInterruptibly,即支持线程中断式地获取共享锁资源
acquireSharedInterruptibly分为两个主要步骤
1.1尝试获取共享资源,即初始化时设置的state是否已经倒计时到0
1.2获取共享资源失败后执行支持线程中断的获取共享锁资源
我们可以这样简单的理解,await方法的本质就是查看state是否归0,归0就直接结束。如果不归0就继续等到state归0,如果知道state归0呢,那就是死循环查询加主动等待的搭配操作。
state尚未归零则执行支持线程中断的获取共享锁资源,正如上面所说死循环查询加主动等待的搭配操作。和aqs的思想一样
2.1插入一个共享模式的节点到队尾
2.2开启死循环查询。因为只有前继前节点是头结点才可以尝试获取共享资源
2.3如果前继前节点是头结点,并且获取到state已经归0。则将该节点设置为头结点,并且传播到后继节点,即如果后继节点是共享模式,且waitStatus正常,则唤醒该节点的线程。
waitStauts主要有以下几个值
CANCELLED=1 线程已经被取消
SIGNAL=-1 后续线程需要被唤醒
CINDITION=-2 线程在等待某个条件
PROPAGATE=-3 下一个AcquireShared应无条件传播
2.4如果前继前节点不是头结点或者state计数尚未归零则park当前线程
3.1查询是否可以park当前线程,前继节点需要为SIGNAL
3.2park当前线程,并且返回线程状态是否被打断
3.countdown方法
countdown方法就很好猜了
1.递减state
2.当state归零的时候唤醒node队列中的状态为SIGNAL(SIGNAL是在判断是否需要park的时候设置的)的线程