前言
CountDownLatch字面意思是倒计时门闩,是基于AQS共享锁实现的,主要有两个方法,countDown方法和await方法。创建CountDownLatch时会指定count数量,count不为0时调用await方法线程会阻塞,每调用一次countDown方法会将count减1,直到count==0时await方法才会解除阻塞。
使用方式
先来看看使用方法,主要有以下两种:
第一种:
主线程等待子线程执行完任务再往下执行,伪代码如下
class Driver2 { // ...
public static void main(String[] args) {
CountDownLatch doneSignal = new CountDownLatch(N);
Executor e = Executors.newFixedThreadPool(10);
for (int i = 0; i < N; ++i) // create and start threads
e.execute(new WorkerRunnable(doneSignal, i));
doneSignal.await(); // wait for all to finish
}
}
}
class WorkerRunnable implements Runnable {
private final CountDownLatch doneSignal;
private final int i;
WorkerRunnable(CountDownLatch doneSignal, int i) {
this.doneSignal = doneSignal;
this.i = i;
}
public void run() {
try {
doWork(i);
doneSignal.countDown();
} catch (InterruptedException ex) {} // return;
}
void doWork() { ... }
}
第二种:
多个子线程等待主线程的发号施令,主线程等待子线程完成后往下执行,伪代码如下:
class Driver {
public static void main(String[] args) {
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(); // don't let run yet
startSignal.countDown(); // let all threads proceed
doSomethingElse();
doneSignal.await(); // wait for all to finish
}
}
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() { ... }
}
二、源码解析
1.内部类Sync
既然是基于AQS实现,那么就必须继承AQS,实现对应的方法,然后再确定AQS中的state属性在该实现类中代表什么含义。在CountDownLatch中,state代表的含义就是count。
// 先看看构造方法
public CountDownLatch(int count) {
if (count < 0) throw new IllegalArgumentException("count < 0");
this.sync = new Sync(count);
}
private static final class Sync extends AbstractQueuedSynchronizer {
Sync(int count) {
setState(count); // state即为count
}
int getCount() {
return getState();
}
// 获取锁,count为0获取锁成功,不为0获取锁失败
protected int tryAcquireShared(int acquires) {
return (getState() == 0) ? 1 : -1;
}
// 释放锁,调用一次count减1,如果count==0返回释放成功,否则失败
protected boolean tryReleaseShared(int releases) {
// Decrement count; signal when transition to zero
for (;;) {
int c = getState();
if (c == 0)
return false;
int nextc = c-1;
if (compareAndSetState(c, nextc))
return nextc == 0;
}
}
}
主要方法
countDown()
AQS方法,释放锁。会调用上面实现的tryReleaseShared,如果该方法返回true,则会唤醒因获取该锁而阻塞的线程,并且可以往后传播。
将count减1,如果count==0则唤醒所有await等待线程,因为是共享锁,可以传播。
public void countDown() {
sync.releaseShared(1);
}
await()
AQS方法,获取锁,获取失败则阻塞。会调用上面实现的tryAcquireShared至少一次。
public void await() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}