CountDownLatch 是一个同步工具类,它可以让一个或多个线程处于等待状态,直到其它的线程执行完毕再执行。
CountDownLatch 使用一个给定的计数值初始化,调用countDown()方法会使计数值减1,处于等待状态的方法在计数值变为0前一直阻塞,当计数值变为0时所有处于等待状态的线程会被释放,这个过程是一次性的,计数值不能被重置。如果需要重置计数值循环这个过程,可以考虑使用CyclicBarrier.
另一个典型的用法就是将一个问题分解成多个线程来执行,主线程等待所有的子线程执行完毕后,主线程再继续执行。
CountDownLatch 使用一个给定的计数值初始化,调用countDown()方法会使计数值减1,处于等待状态的方法在计数值变为0前一直阻塞,当计数值变为0时所有处于等待状态的线程会被释放,这个过程是一次性的,计数值不能被重置。如果需要重置计数值循环这个过程,可以考虑使用CyclicBarrier.
CountDownLatch 作为一个同步工具类可以被用作多种目的。比如将初始计数值设置为1就像设置了一个开关或者一扇门,所有线程调用await()方法在这扇门处处于等待状态,当一个线程调用countDown()方法后,计数值变为0,门会被打开,所有处于等待状态的线程开始执行。将初始值设置为N,可以让一个线程处于等待状态,等待N个线程完成后,或者某个动作被执行N次后再开始执行。像下面的例子一样:
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(); //所有Worker线程都处于等待状态,只执行doSomethingElse()
startSignal.countDown(); //准许所有Worker线程开始执行
doSomethingElse();
doneSignal.await(); //等待所有Worker线程执行完毕
}
}
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(); //所有Worker线程执行到这里变为等待状态,在 startSignal.countDown()调用后继续执行
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) //启动多个子线程来处理问题
e.execute(new WorkerRunnable(doneSignal, i));
doneSignal.await(); //等待所有子线程处理完毕
doSomethingElse();
}
}
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() { ... }
}