CountDownLatch(闭锁)初始化时设置等待数量,countDown()可以减1,await()在等待数量大于0时会使线程等待。
CountDownLatch初始化时,设置AQS的state。执行await方法时,将Node加入到等待队列中,挂起线程。执行countDown方法state-1,state为0时,唤醒等待队列中的线程。
比如跑步比赛模拟:CountDownLatch初始化时,state是运动员数量。运动员到达终点时,执行countDown方法。所有运动员到达终点时,唤醒线程,统计比赛结果。
比如Excel分析:分析多个Excel,CountDownLatch初始化时,state是Excel的数量。并发分析,分析结束一个,执行一次countDown方法。都分析结束后,唤醒线程,统计结果进行新的分析。
下面以跑步比赛为例展示CountDownLatch:
public class CountDownLatchDemo {
/**
* 运动员数量
*/
private static int athleteCount = 10;
/**
* 所有运动员准备起跑,同一把发令枪
*/
private static CountDownLatch commandCountDownLatch =new CountDownLatch(1);
/**
* 所有运动员到达终点,toEndCountDownLatch不再等待
*/
private static CountDownLatch toEndCountDownLatch =new CountDownLatch(athleteCount);
public static void main(String[] args) {
for (int i = 0; i < athleteCount; i++) {
Thread athlete = new Thread(() -> {
try {
commandCountDownLatch.await(); // commandCountDownLatch计数为0时线程不再等待
System.out.println(Thread.currentThread().getName() + "到达终点!");
toEndCountDownLatch.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
athlete.setName("运动员" + (i + 1) + "号");
athlete.start();
}
System.out.println("发令枪响了,比赛开始!");
commandCountDownLatch.countDown();
try {
toEndCountDownLatch.await(); // toEndCountDownLatch计数为0时线程不再等待
System.out.println("所有运动员到达终点,比赛结束!");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
结果:
发令枪响了,比赛开始!
运动员2号到达终点!
运动员1号到达终点!
运动员3号到达终点!
运动员4号到达终点!
运动员5号到达终点!
运动员6号到达终点!
运动员7号到达终点!
运动员8号到达终点!
运动员9号到达终点!
运动员10号到达终点!
所有运动员到达终点,比赛结束!