简介
CountDownLatch 是一个倒数器,像是一个发令枪。
- 构造参数 N 倒计时起始数据(N=3,则从3开始数,3,2,…)
- countDown()方法就是执行一次倒数,N就减一
- await() 在当前计数到达零之前,await 方法会一直受阻塞
所以可以利用这一特性,同时唤醒多个等待的线程。
示例代码实现:
- 提交5个任务
- 前3个同时开始执行
- 任务提交完毕后,主线程阻塞,直到有4个任务完成
- 然后主线程继续执行
- 等待线程池优雅停止
代码
public class CountDownLatchDemo {
public static void main(String[] args) throws Exception {
ExecutorService exe =Executors.newFixedThreadPool(5);
/**
* 前3个一起执行
* 4个做完 有信号
*/
CountDownLatch startLatch = new CountDownLatch(3);
CountDownLatch doneSignal = new CountDownLatch(4);
for (int i = 0; i < 5; i++) {
exe.execute(new WaitTask(startLatch, doneSignal));
startLatch.countDown();
TimeUnit.MILLISECONDS.sleep(300);
}
PrintUtil.print("waiting four done ");
doneSignal.await();
PrintUtil.print("four done ");
exe.shutdown();
}
}
public class WaitTask implements Runnable {
private static int counter = 0;
private final int id = counter++;
private final CountDownLatch latch;
private final CountDownLatch doneSignal;
public WaitTask(CountDownLatch latch, CountDownLatch doneSignal) {
this.latch = latch;
this.doneSignal = doneSignal;
PrintUtil.print(this + "construct ");
}
@Override
public void run() {
try {
latch.await();
PrintUtil.print(this + "after run await");
working();
} catch (InterruptedException e) {
PrintUtil.print("InterruptedException" + this);
}
doneSignal.countDown();
PrintUtil.print(this + "done!");
}
@Override
public String toString() {
return "WaitTask{" +
"id=" + id + "} :";
}
private void working() throws InterruptedException {
PrintUtil.print(this + "working");
Thread.sleep(1000);
}
}
优雅停止
exe.shutdown();
线程池不再接受新提交的任务,但会执行完所有已提交的任务,然后退出。
结果
WaitTask{id=0} :construct
WaitTask{id=1} :construct
WaitTask{id=2} :construct
WaitTask{id=2} :after run await
WaitTask{id=0} :after run await
WaitTask{id=1} :after run await
WaitTask{id=0} :working
WaitTask{id=2} :working
WaitTask{id=1} :working
WaitTask{id=3} :construct
WaitTask{id=3} :after run await
WaitTask{id=3} :working
WaitTask{id=4} :construct
WaitTask{id=4} :after run await
WaitTask{id=4} :working
waiting four done
WaitTask{id=0} :done!
WaitTask{id=1} :done!
WaitTask{id=2} :done!
WaitTask{id=3} :done!
four done
WaitTask{id=4} :done!