学习一个东西,一定要搞清楚使用的场景和局限,才能在合适的场景下使用。
CountDownLatch 是Java并发包中的一个同步助手类,用于同步多线程。
具体的用法可以总结成一句话:
如果有A组和B组两组线程,每组由一个或者多个线程组成(意味着 两个线程组的关系为 1对1,1对多,多对多,多对一),那么可以实现A组等待B组,或者B组等待A组,即一方完成(全部调用countdown方法),另外一方才开始(调用await方法的线程)的效果。
具体到应用中,可以完成诸如
- 一个开关,由一个线程打开(为一个线程或者多个),或者多个线程打开(为一个线程或者多个)
- 等待一组分派的任务完成(多个线程countdown,一个线程await)
- 命令一组任务开始(多个线程await,一个线程countdown)
具体的应用我们也可以参考Java API 提供的经典的例子。
作为开关
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(); // 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() { ... }
}
作为分派
class Driver2 { // ...
void main() throws InterruptedException {
CountDownLatch doneSignal = new CountDownLatch(N);
Executor e = ...
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() { ... }
}
其实本质上都可以看成是一种开关。