1、CountDownLatch简介
(1)简单概念:在线程池中使用多线程执行一些任务时,这些线程当达到某一个条件后,才能开始各自去执行各自的任务。如果该条件没有达到,那么这些线程一直阻塞在那里,等待条件满足之后才会往下执行。
(2)CountDownLatch就是(1)中提到的条件,只是该条件是类似于倒计时,只有倒计时到0的时候,才视为达到条件。所以CountDownLatch是通过倒计时并结束为0的时候,之前阻塞的线程才会像疯狗一样各自抢着往下执行。否则所有线程一直阻塞。CountDownLatch最重要的方法是countDown()和await(),前者主要是倒数一次(就是调用countDown方法则时间减一,注意CountDownLatch时手动倒计时,不是自动),后者是等待倒数到0,如果没有到达0,就只有阻塞等待了,如果等于0,则开始各自执行。
(3)CountDownLatch扩展功能思路:CountDownLatch可以实现一个人(也可以是多个人)等待其他人都来通知他,也可以实现一个人通知多个人的效果。比如类似于裁判一声口令,运动员同时开始奔跑,或者所有运动员都跑到终点后裁判才可以公布结果。用这个功能做百米赛跑的游戏程序不错哦。还可以实现一个计划需要多个领导都签字后才能继续往下实施的情况。
2、CountDownLatch的方法介绍
public void countDown()
countdown方法递减锁存器的计数,如果计数到达零,则释放所有等待的线程。如果当前计数大于0,则将计数减一,如果新的计数为0,出于线程调度目的,将重新启用所有的等待的线程。
public boolean await(long timeout,
TimeUnit unit)
throws InterruptedException
true
值。
如果当前计数大于零,则出于线程调度目的,将禁用当前线程,且在发生以下三种情况之一前,该线程将一直处于休眠状态:
- 由于调用
countDown()
方法,计数到达零;或者 - 其他某个线程中断当前线程;或者
- 已超出指定的等待时间。
如果计数到达零,则该方法返回 true
值。
如果当前线程:
- 在进入此方法时已经设置了该线程的中断状态;或者
- 在等待时被中断,
则抛出 InterruptedException
,并且清除当前线程的已中断状态。如果超出了指定的等待时间,则返回值为 false
。如果该时间小于等于零,则此方法根本不会等待。
-
参数:
-
timeout
- 要等待的最长时间 -
unit
-timeout
参数的时间单位。
返回:
-
如果计数到达零,则返回
true
;如果在计数到达零之前超过了等待时间,则返回false
抛出:
-
InterruptedException
- 如果当前线程在等待时被中断
以下是百米赛跑的demo
public class CountDownLatchDemo {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(5);
final CountDownLatch begin = new CountDownLatch(1);
final CountDownLatch personCount = new CountDownLatch(5);
for(int i=0;i<5;i++){
executorService.execute(new Runnable() {
@Override
public void run() {
System.out.println("线程"+Thread.currentThread().getName()+"准备好,等待命令");
try {
begin.await();
System.out.println("线程"+Thread.currentThread().getName()+"接到命令,跑");
Thread.sleep((long)(Math.random()*1000));
System.out.println("线程"+Thread.currentThread().getName()+"跑到达终点");
personCount.countDown();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
try {
System.err.println("线程"+Thread.currentThread().getName()+"发布命令->准备");
Thread.sleep(500);
System.err.println("线程"+Thread.currentThread().getName()+"发布命令->开始");
begin.countDown();
personCount.await();
System.err.println("线程"+Thread.currentThread().getName()+"获取到的比赛结果是:……");
} catch (InterruptedException e) {
e.printStackTrace();
}
executorService.shutdown();
}
}