CountDownLatch的作用是:允许一个或多个线程等待,直到一组在其他线程中执行的操作完成。
CountDownLatch使用给定的一个数值(计数器)进行初始化,当调用await方法时,线程会被阻塞直到CountDownLatch计数器的值变成0。调用countDown方法计数器就会减一。
直接看javadoc提供的demo
demo1:使用一个开始信号来阻塞所有线程的运行,直到Dirver(主线程)准备OK。
使用一个完成信号让Dirver(主线程)阻塞,直到所有线程运行完成。
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() { ... } }
有两个CountDownLatch 的实例,startSignal(开始信号) 和 doneSignal(完成信号)。
Driver 类的main方法启动了N个Worker线程,所有Worker线程在运行到startSignal.await()时会被阻塞直到Driver的main里面startSignal.countDown()被执行。
Driver 类的main方法执行到doneSignal.await()时,main线程就会阻塞直到N个Worker线程运行完成。doneSignal的计数器值为N,每个Worker线程运行完成后都会调用doneSignal.countDown()方法(使得doneSignal的计数器减一),当doneSignal的计数器减到0时,main线程将不再阻塞。
demo2
将一个任务分解为N个部分,当每个部分都运行完成后,主线程才继续往下运行
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() { ... } }