CountDownLatch是一个同步工具类,用来协调多个线程之间的同步,或者说起到线程之间的通信(而不是用作互斥的作用)。
CountDownLatch能够使一个线程在等待另外一些线程完成各自工作之后,再继续执行。使用一个计数器进行实现。计数器初始值为线程的数量。当每一个线程完成自己任务后,计数器的值就会减一。当计数器的值为0时,表示所有的线程都已经完成一些任务,然后在CountDownLatch上等待的线程就可以恢复执行接下来的任务。
使某一个线程在某些其他线程任务执行成功后才开始执行,简单来说就是:
现在有两个线程:
老师线程,考生线程
考试开始
考生开始答题
考试结束
老师收卷
老师线程不允许在考生线程执行时候收卷
上代码
学生class
/**
* @author jojo
*/
public class Student implements Runnable{
private CountDownLatch countDownLatch;
private String name;
public Student(CountDownLatch countDownLatch, String name){
this.countDownLatch = countDownLatch;
this.name = name;
}
@Override
public void run() {
System.out.println(this.name+"正在答卷");
try{
TimeUnit.SECONDS.sleep(1);
}catch(InterruptedException ie){}
System.out.println(this.name+"答卷完毕");
this.countDownLatch.countDown();
}
}
老师class
/**
* @author jojo
*/
public class Teacher implements Runnable{
private CountDownLatch countDownLatch;
public Teacher(CountDownLatch countDownLatch){
this.countDownLatch = countDownLatch;
}
@Override
public void run() {
System.out.println("老师正在等待学生答卷结束");
try{
this.countDownLatch.await();
}catch(InterruptedException e){}
System.out.println("学生全部答卷结束,老师开始收卷");
}
}
考场Main方法
public class TestRoom {
public static void main(String[] args) throws Exception {
ExecutorService threadPool = new ThreadPoolExecutor(1,3,
10, TimeUnit.SECONDS,new LinkedBlockingDeque<>());
CountDownLatch countDownLatch = new CountDownLatch(3);
Student sA = new Student(countDownLatch,"A");
Student sB = new Student(countDownLatch,"B");
Student sC = new Student(countDownLatch,"C");
Teacher teacher = new Teacher(countDownLatch);
// 开始考试
threadPool.execute(sA);
threadPool.execute(sB);
threadPool.execute(sC);
threadPool.execute(teacher);
threadPool.shutdown();
}
}
执行结果:
方法源码解析
构造方法
学生调用的执行任务方法
老师调用的监考和收卷方法
当然,老师的await也不可能无限等待下去,当发生两种情况时,也会导致当前线程任务被释放
- 当前线程执行状态被中断
- 超出了指定的等待时间
CountDownLatch的不足
CountDownLatch是一次性的,计算器的值只能在构造方法中初始化一次,当CountDownLatch递减至0使用完毕后,不能再次被设值使用。