CountDownLatch 是一个通用同步工具,它有很多用途。将计数 1 初始化的CountDownLatch 用作一个简单的开/关锁存器,或入口:在通过调用countDown()
的线程打开入口前,所有调用await
的线程都一直在入口处等待。用N 初始化的 CountDownLatch 可以使一个线程在 N 个线程完成某项操作之前一直等待,或者使其在某项操作完成 N 次之前一直等待。
下面的例子模拟 一个命令发出者和三个命令接受者,三个命令接受者首先阻塞在命令发出者,当命令发出后,三个接受者接收到命令开始执行相应的操作,同时命令发出者阻塞等待所有的接受者完成。类似于赛跑,所有运动员站到起跑线后都在等待裁判发出命令,运动员接受到命令后开始奔跑,当所有运动员跑到终点后,裁判宣布赛跑结果。代码如下:
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ContdownLatchTest {
/**
* @param args
*/
public static void main(String[] args) {
ExecutorService service = Executors.newCachedThreadPool();
final CountDownLatch cdOrder = new CountDownLatch(1);
final CountDownLatch cdAnswer = new CountDownLatch(3);
for(int i=0; i<3; i++){
Runnable runnable = new Runnable(){
public void run() {
try{
System.out.println("线程" + Thread.currentThread().getName() +
"正准备接受命令");
cdOrder.await();
System.out.println("线程" + Thread.currentThread().getName() +
"已接受命令");
Thread.sleep((long) (Math.random()*10000));
System.out.println("线程" + Thread.currentThread().getName() +
"回应命令处理结果");
cdAnswer.countDown();
}catch(Exception e){
e.printStackTrace();
}
}
};
service.execute(runnable);
}
try{
Thread.sleep((long) (Math.random()*10000));
System.out.println("线程" + Thread.currentThread().getName() +
"即将发布命令");
cdOrder.countDown();
System.out.println("线程" + Thread.currentThread().getName() +
"已经发送命令,正在等待结果");
cdAnswer.await();
System.out.println("线程" + Thread.currentThread().getName() +
"已收到所有响应结果");
}catch(Exception e){
e.printStackTrace();
}
service.shutdown();
}
}
下面的例子是jdk中的说明:
将一个问题分成 N 个部分,用执行每个部分并让锁存器倒计数的 Runnable 来描述每个部分,然后将所有 Runnable 加入到 Executor 队列。当所有的子部分完成后,协调线程就能够通过 await。(当线程必须用这种方法反复倒计数时,可改为使用CyclicBarrier
。)
代码如下:
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() { ... }
}