CountDownLatch
CountDownLatch 是java.util.concurrent
包中的类,初始化时需要一个正整数参数作为初始 status 值,Thread#1 中每次调用它的countDown()
方法都使得 status 减一,Thread#2 中调用它的await()
方法会导致 Thread#2 阻塞直到 status 为0。
它可以用来设置一个任务阻塞直到其他 n 个相互独立的任务结束。
JDK1.8 源码注释中的一个例子如下:
class Driver { // ...
void main() throws InterruptedException {
CountDownLatch startSignal = new CountDownLatch(1);
CountDownLatch doneSignal = new CountDownLatch(N);
for (int i = 0; i < N; ++i) // create and start threads
new Thread(new Worker(startSignal, doneSignal)).start();
doSomethingElse(); // 开始前的准备工作
startSignal.countDown(); // 使得所有的工作线程开始
doSomethingElse();
doneSignal.await(); // 等待所有工作线程结束
}
}
class Worker implements Runnable {
private final CountDownLatch startSignal;
private final CountDownLatch doneSignal;
Worker(CountDownLatch startSignal, CountDownLatch doneSignal) {
this.startSignal = startSignal;
this.doneSignal = doneSignal;
}
public void run() {
try {
startSignal.await(); // 等待开始信号
doWork();
doneSignal.countDown(); // 执行完任务后通知管理者
} catch (InterruptedException ex) {} // return;
}
void doWork() { ... }
}
源码分析:
CountDownLatch 只有一个同步器字段,它是一个内部类的 final 实例,这个内部类是 java.util.concurrent.locks
包中的 AbstractQueuedSynchronizer 的子类,重写了父类的 tryAcquireShared、tryReleaseShared 方法。它是一个共享式队列同步器。
AQS 要求子类重写的这两个方法,必须是非阻塞、线程安全的。
private final Sync sync; // CountDownLatch 构造时用正整数参数来初始化
private static final class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = 4982264981922014374L;
Sync(int count) {
setState(count);
}
int getCount() {
return getState();
}
// 共享模式下,询问同步器当前 status 的值的状态,来表示现在是否能获得同步器
protected int tryAcquireShared(int acquires) {
return (getState() == 0) ? 1 : -1;
}
// 共享模式下,修改同步器的 status 值,来表示释放的动作
protected boolean tryReleaseShared(int releases) {
// 如果同步锁的 status 已经为 0,就返回 false。
// 否则当前线程将 status减 1;
// 操作成功时,如果减小后的新值为 0,返回 true,否则返回 false
for (;;) {
int c = getState();
if (c == 0)
return false;
int nextc = c-1;