CountDownLatch类位于java.util.concurrent包下,利用它可以实现类似计数器的功能。比如有一个任务A,它要等待其他4个任务执行完毕之后才能执行,此时就可以利用CountDownLatch来实现这种功能。
countdownlatch内部通过继承AQS实现的一个sync来实现。重写了tryAcquireShared 和tryReleaseShared 方法。
countdownlatch常用的方法如下:
countdownlatch的构造函数,传入一个int,即当int数的线程执行完之后,再执行接下来的任务。
countdown方法,当线程执行完之后,调用此方法,会使count值减1.
await 方法,当前线程会一直阻塞直到count变为0才会继续执行。即当其他的线程都执行完成,当前线程才会执行。
下面通过一个例子来介绍countdownlatch的使用。在运动会跑步场景,所有的运动员在跑道上准备好之后,发令员才会发令起跑。当所有的运动员到达终点之后才会进行颁奖。
package com.macro.mall.demo.thread;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.*;
/**
* 让若干个子线程都完成任务后,主线程再继续执行任务
*
* 例子:当所有的选手准备就绪后,裁判员发令,运动员一起起跑
* 当所有的运动员跑完之后再进行颁奖。
*/
public class CountDownLatchDemo {
static String[] names = {"小王","小李","小张","小力","小白"};
static long[] times ={3000,4000,5000,6000,7000};
public static void main(String[] args) {
//发令枪 只需要响一下
CountDownLatch start = new CountDownLatch(1);
//完成计数器
CountDownLatch finish = new CountDownLatch(names.length);
//线程池
ExecutorService executorService = Executors.newFixedThreadPool(10);
System.out.println(getTIme()+"请所有选手入场");
for(int i=0;i<names.length;i++){
final int idx=i;
Runnable runnable = new Runnable() {
@Override
public void run() {
try {
System.out.println(getTIme() + names[idx] + "准备就绪");
//等待发令枪响
start.await();
//开始跑步
System.out.println(getTIme() + names[idx]+"开始跑步");
Thread.sleep(times[idx]);
System.out.println(getTIme() +names[idx]+"完成跑步");
} catch (Exception e){
e.printStackTrace();
}finally {
//一名选手跑完了,完成计数器-1
finish.countDown();
}
}
};
executorService.submit(runnable);
}
//所有选手准备就绪完成,发令枪响
try {
Thread.sleep(1);
System.out.println(getTIme()+"发令枪响");
start.countDown();
//所有选手完成后,进行颁奖
finish.await();
System.out.println(getTIme()+"现在开始颁奖");
}catch (Exception e){
e.printStackTrace();
}finally {
executorService.shutdown();
}
}
private static String getTIme(){
Date date = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("hh:mm:ss");
return simpleDateFormat.format(date);
}
}
执行结果如下:可以看到所有选手准备就绪之后才发令,所有选手跑步完之后才进行颁奖。