CountDownLatch
简介
是一个同步工具类,用来协调多个线程之间的同步
应用场景
1.某一线程在开始运行前等待n个线程执行完毕。将CountDownLatch的计数器初始化为new CountDownLatch(n),每当一个任务线程执行完毕,就将计数器减1 ,countDown(),当计数器的值变为0时,在await()的线程就会被唤醒。典型应用场景就是启动一个服务时,主线程需要等待多个组件加载完毕,之后再继续执行。
2.实现多个线程开始执行任务的最大并行性。注意是并行性,不是并发,强调的是多个线程在某一时刻同时开始执行。类似于赛跑,将多个线程放到起点,等待发令枪响,然后同时开跑。做法是初始化一个共享的CountDownLatch(1),将其计算器初始化为1,多个线程在开始执行任务前首先countdownlatch.await(),当主线程调用countDown()时,计数器变为0,多个线程同时被唤醒。
缺点
计算器的值只能在构造方法中初始化一次, CountDownLatch使用完毕后,它不能再次被使用
代码示例
public class CountDownLatchDemo implements Callable<Integer> {
static int TheadCount = 15;
static int awaitMillisecond = 3000;
static CountDownLatch countDownLatch = new CountDownLatch(TheadCount);
int id;
public CountDownLatchDemo(int id) {
this.id = id;
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
boolean fireFlag = true;
ExecutorService executorService = Executors.newFixedThreadPool(TheadCount);
ArrayList<Future<Integer>> list = new ArrayList<>();
for (int i=0;i<TheadCount;i++){
Future<Integer> submit = executorService.submit(new CountDownLatchDemo(i));
list.add(submit);
}
for (int i=0;i<TheadCount;i++){
Future<Integer> future = list.get(i);
if (0==future.get()){
fireFlag=false;
break;
}
}
if (fireFlag){ //当计数器为0时,线程被唤醒
System.out.println(getCurrentTime()+"fire");
}else {
System.out.println(getCurrentTime()+"countDownLatch.await()");
countDownLatch.await(awaitMillisecond, TimeUnit.MILLISECONDS);
System.out.println(getCurrentTime()+Thread.currentThread().getName()+",线程阻塞");
countDownLatch.await(); //线程阻塞
System.out.println(getCurrentTime() + "thread contains error, do not fire.");
}
executorService.shutdown();
}
@Override
public Integer call() {
try {
if (id<15){
System.out.println(getCurrentTime()+Thread.currentThread().getName()+",检查完毕");
//执行完一个线程,计数器-1,
countDownLatch.countDown();
return 1;
}else {
System.out.println(getCurrentTime()+Thread.currentThread().getName()+",存在异常,检查中");
Thread.sleep(awaitMillisecond);
System.out.println(getCurrentTime()+Thread.currentThread().getName()+",检查失败");
return 0;
}
} catch (Exception e) {
System.out.println("call Exception");
return 0;
}
}
private static String getCurrentTime(){
Date date = new Date();
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
String s = format.format(date);
String ret ="["+s+"]";
return ret;
}
}