CountDownLatch解析
CountDownLatch学习
CountDownLatch简介
CountDownLatch是一个同步辅助工具类,它允许一个或多个线程等待直到其他线程中一系列操作完成。latch有闭锁的意思,所以CountDownLatch又称闭锁。
CountDownLatch初始化时必须给定一个count值,用来表示事件总数。每次调用countDown方法事件数就会减一,只要count值不为0线程就会一直处于等待状态或者等待线程超时及中断。等到count值为0时,await方法就是释放,此时所有的线程开始运行。
countDownLatch就像田径比赛一样,当每有一个运动员准备完毕计数器就减一,等到所有人都准备完毕之后,发令枪一响所有运动员开跑,谁跑的最快谁就优先获取到CPU的执行权。
CountDownLatch必须在初始化时指定count值,而且count值一旦被初始化之后不能再重新设置值。
如果需要可变的版本可以考虑使用CyclicBarrier。
CountDownLatch使用场景
1、确保一个服务不会开始,直到其依赖的其他服务都已经开始。每一个服务都包含一个二元闭锁,开启服务S首先会等待闭锁S依赖的其他服务,在启动结束后,这些所有依赖S的服务也都可以处理了。
2、等待,直到所有活动部分都已为继续处理做好准备,比如王者荣耀或者英雄联盟这类游戏,在匹配玩家的时候只有所有玩家都确认之后才能到选择英雄界面,也就是终点状态。
诸如此类的问题的都可以使用CountDownLatch。
CountDownLatch使用
CountDownLatch方法
CountDownLatch中主要用到的方法有三个:
1、countDown():减少闭锁的count值,当count值到达0时,释放所有等待中的线程。
2、await() :当前线程会处于等待状态,知道count值为0,除非当前线程中断否则会一直等待。当count为0时,await方法会立即返回。如果count值大于0,当前线程就不会被调度并且处于休眠状态,除非以下两种情况发生:
1、count值到达0;
2、其他线程中断了当前线程。
3、await(long timeout, TimeUnit unit) :当count到达0时返回true,当超过等待时间后返回false;该方法和无参的await方法一样,只不过就是多了等待时间而已。
例子:
public class CountDownDemo {
private static final int N = 5;
private static CountDownLatch countDownLatch = new CountDownLatch(N);
private static class ServiceThread implements Runnable{
@Override
public void run() {
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getId()+" await.....");
}
}
private static class CountDownThread implements Runnable{
@Override
public void run() {
countDownLatch.countDown();
System.out.println(Thread.currentThread().getId()+" countDown.....");
}
}
public static void main(String[] args) throws InterruptedException {
System.out.println("MainThread start");
new Thread(new ServiceThread()).start();
for (int i = 0; i < N - 1; i++) {
new Thread(new CountDownThread()).start();
}
countDownLatch.countDown();
countDownLatch.await();
System.out.println("MainThread end");
}
}
运行结果:
MainThread start
11 countDown.....
12 countDown.....
13 countDown.....
14 countDown.....
MainThread end
15 await.....
N初始化为5个,代表有5个线程进行处理,ServiceThread调用await阻塞当前线程运行,CountDownThread 对count进行递减。
从打印结果可以看出,ServiceThread虽然先启动了,但是却一直在阻塞处于等待状态,当count值递减到0是才变成运行状态。当把循环外的countdown方法注释掉,线程会一直处于等待状态,直到count值变为0。