CountDownLatch ,juc下的同步工具类,简称闭锁。
它允许一条或者多条线程等待其他一条或者多条线程执行完成后执行。
CountDownLatch 是通过一个计数器来实现的,计数器的初始值为线程的数量。
每当一个线程完成了任务后,计数器的值就会减 1。
当计数器为 0 时,表示所有的线程都已经完成了任务,
这时候在闭锁上等待的线程(即之前调用countDownLatch.await()方法的线程)
就可以恢复被唤醒然后执行任务。
应用场景为:
- 某一条线程在开始执行前必须要等待其他n个线程执行完毕
像如果要启动一个服务时,但是这个服务又必须依赖其他组件,所以必须得
先等待其他组件启动完毕,然后再启动服务。
统计需要启动的依赖组件数量为10,然后构建一个CountDownLatch,
CountDownLatch countDownLatch = new CountDownLatch(10);
就是在启动服务前调用countDownLatch.await(),使启动服务那条线程先阻塞等待。
每启动完一个组件,调用 一下 countDownLatch.countDown();
直到计数为0了,则唤醒启动服务的那条线程,开始启动服务。
2.可以实现多条线程并行执行(在同一时刻同时开始执行)。
类似跑步比赛,把各个运动员当做一条线程,每条线程已经在起点做好准备
(即各个运动员都准备好了),这时候就在等待裁判发令枪响。
这就相当于构建一个数量为1的计数器
CountDownLatch countDownLatch = new CountDownLatch(1);
然后各个运动员都在等待(都调用了countDownLatch.await()方法)裁判信号。
这时候当裁判发令枪响时(相当于调用了countDownLatch.countDown()方法),这时候
相当于提醒各个运动员可以开始跑步了(唤醒了各个运动员)。
场景1的代码例子,场景2的代码例子反过来就是了(把await方法和countDown方法互换地方)
public class TestCountDownLatch {
public static void main(String[] args) throws Exception{
//用 5 条线程来启动依赖组件
ExecutorService executorService = Executors.newFixedThreadPool(5);
//启动服务前需要依赖 10 个组件先启动
System.err.println("------启动服务前先加载其他组件----");
int size = 10;
CountDownLatch countDownLatch = new CountDownLatch(size);
for (int i = 1; i <= size; i++) {
final int temp = i;
executorService.execute(() ->{
try {
//模拟组件启动时间
Thread.sleep(new Random().nextInt(2000));
System.err.println(String.format("线程-%s,-- 加载完成组件 %d", Thread.currentThread().getName(), temp));
}catch (Exception e){
e.printStackTrace();
}finally {
countDownLatch.countDown();
}
});
}
countDownLatch.await();
System.err.println("------启动服务完成----");
executorService.shutdown();
}
控制台输出如下
------启动服务前先加载其他组件----
线程-pool-1-thread-2,-- 加载完成组件 2
线程-pool-1-thread-1,-- 加载完成组件 1
线程-pool-1-thread-4,-- 加载完成组件 4
线程-pool-1-thread-2,-- 加载完成组件 6
线程-pool-1-thread-2,-- 加载完成组件 9
线程-pool-1-thread-5,-- 加载完成组件 5
线程-pool-1-thread-3,-- 加载完成组件 3
线程-pool-1-thread-1,-- 加载完成组件 7
线程-pool-1-thread-2,-- 加载完成组件 10
线程-pool-1-thread-4,-- 加载完成组件 8
------启动服务完成----
网友评论