概述
CountDownLatch 是并发包中的一个工具类,它的典型应用场景为:一个线程等待几个线程执行,待这几个线程结束后,该线程再继续执行。
CountDownLatch的通常用法和Thread.join()有点类似,等待其它线程都完成后再执行主任务。
简单起见,可以把它理解为一个倒数的计数器:初始值为线程数,每个线程结束时执行减 1 操作,当计数器减到 0 时等待的线程再继续执行。
类结构图和方法
CountDownLatch没有实现Serializable接口,所以它不是可序列化的。
其中两个 await 都是让当前线程进入等待状态(获取资源失败);而 countDown 方法是将计数器减去 1,当计数器为 0 的时候,那些处于等待状态的线程会继续执行(获取资源成功)。
源码分析
构造方法:
public CountDownLatch(int count) {
if (count < 0) throw new IllegalArgumentException("count < 0");
this.sync = new Sync(count);
}
构造器(该构造器是唯一的)传入一个正整数,且初始化了 sync 变量,Sync 是内部的一个嵌套类,继承自 AQS。
静态内部类:
private static final class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = 4982264981922014374L;
// 传入初始次数
Sync(int count) {
setState(count);
}
// 获取还剩的次数
int getCount() {
return getState();
}
// 尝试获取共享锁
protected int tryAcquireShared(int acquires) {
// 注意,这里state等于0的时候返回的是1,也就是说count减为0的时候获取总是成功
// state不等于0的时候返回的是-1,也就是count不为0的时候总是要排队
return (getState() == 0) ? 1 : -1;
}
// 尝试释放锁
protected boolean tryReleaseShared(int releases) {
for (;;) {
// state的值
int c = getState();
// 等于0了,则无法再释放了
if (c == 0)
return false;
// 将count的值减1
int nextc = c-1;
// 原子更新state的值
if (compareAndSetState(c, nextc))
// 减为0的时候返回true,这时会唤醒后面排队的线程
return nextc == 0;
}
}
}
Sync重写了tryAcquireShared()和tryReleaseShared()方法,并把count存到state变量中去。
await()方法
public void await() throws InterruptedException {
// 调用AQS的acquireSharedInterruptibly()方法
sync.acquireSharedInterruptibly(1);
}
// java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly()
public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
// 尝试获取锁,如果失败则排队
if (tryAcquireShared(arg) < 0)
doAcquireSharedInterruptibly(arg);
}
await()方法是等待其它线程完成的方法,它会先尝试获取一下共享锁,如果失败则进入AQS的队列中排队等待被唤醒。
countDown()方法
public void countDown() {
// 调用AQS的释放共享锁方法
sync.releaseShared(1);
}
// java.util.concurrent.locks.AbstractQueuedSynchronizer.releaseShared()
public final boolean releaseShared(int arg) {
// 尝试释放共享锁,如果成功了,就唤醒排队的线程
if (tryReleaseShared(arg)) {
doReleaseShared();
return true;
}
return false;
}
countDown()方法,会释放一个共享锁,也就是count的次数会减1。
小结
CountDownLatch 可以理解为一个倒数的计数器,它的典型应用场景就是一个线程等待几个线程执行结束后再继续执行。其内部是基于 AQS 的共享模式实现的。整理如下:
(1)CountDownLatch表示允许一个或多个线程等待其它线程的操作执行完毕后再执行后续的操作;
(2)CountDownLatch使用AQS的共享锁机制实现;
(3)CountDownLatch初始化的时候需要传入次数count;
(4)每次调用countDown()方法count的次数减1;
(5)每次调用await()方法的时候会尝试获取锁,这里的获取锁其实是检查AQS的state变量的值是否为0;
(6)当count的值(也就是state的值)减为0的时候会唤醒排队着的线程(这些线程调用await()进入队列);