一、简介
官网的介绍如下:
CountDownLatch:允许一个或多个线程等待直到在其他线程中执行的一组操作完成的同步辅助。
CountDownLatch用给定的计数初始化。 await方法阻塞,直到由于countDown()方法的调用而导致当前计数达到零,之后所有等待线程被释放,并且任何后续的await 调用立即返回。
CountDownLatch使一个线程等待其他线程各自执行完毕后再执行,是通过一个计数器来实现的,计数器的初始值是线程的数量。每当一个线程执行完毕后,计数器的值就-1,当计数器的值为0时,表示所有线程都执行完毕,然后在闭锁上等待的线程就可以恢复工作了。
二、主要API
- 构造方法
//参数count为计数值,一般为线程
public CountDownLatch(int count) {
if (count < 0) throw new IllegalArgumentException("count < 0");
this.sync = new Sync(count);
}
- 常用方法
void |
await() 调用await()方法的线程会被挂起,它会等待直到count值为0才继续执行 |
boolean |
await(long timeout, TimeUnit unit) 和await()类似,只不过等待一定的时间后count值还没变为0的话就会继续执行 |
void |
将count值减1 |
long |
getCount() 返回当前count值 |
三、示例
CountDownLatch的一个非常典型的应用场景是:有一个任务想要往下执行,但必须要等到其他的任务执行完毕后才可以继续往下执行。假如我们这个想要继续往下执行的任务调用一个CountDownLatch对象的await()方法,其他的任务执行完自己的任务后调用同一个CountDownLatch对象上的countDown()方法,这个调用await()方法的任务将一直阻塞等待,直到这个CountDownLatch对象的计数值减到0为止。
举个例子:
五个学生,一个老师,学生们都在自习,只有老师才有教室的一把钥匙,老师必须等到5个学生都离开教室之后才能锁门,不可能学生还没走老师就把教室给锁了,显然存在一个线程阻塞等待另外的线程必须完成之后才可以执行的场景。
代码实现:
public class T01_CountDownLatch {
public static void main(String[] args) {
//模拟五个学生
CountDownLatch countDownLatch = new CountDownLatch(5);
for (int i = 1; i <= 5; i++) {
final int num = i;
new Thread(() -> {
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("学生" + num + "离开教室...");
//将计数器减一
countDownLatch.countDown();
}).start();
}
//老师一直在等待,即主线程一直阻塞
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
//直到计数器变为0时才执行
System.out.println("所有学生都离开了,老师拿钥匙锁门....");
}
}
运行结果:
学生4离开教室...
学生1离开教室...
学生2离开教室...
学生3离开教室...
学生5离开教室...
所有学生都离开了,老师拿钥匙锁门....