CountDownLatch
**
* 倒计数锁存器
*
* 举例:运动员进行跑步比赛时,假设有6个运动员参与比赛,裁判员在终点会为这6个运动员分别计时,
* 可以想象每当一个运动员到达终点的时候,对于裁判员来说就少了一个计时任务。
* 直到所有运动员都到达终点了,裁判员的任务也才完成。这6个运动员可以类比成6个线程,
* 当线程调用CountDownLatch.countDown方法时就会对计数器的值减一,
* 直到计数器的值为0的时候,裁判员(调用await方法的线程)才能继续往下执行
*/
public class CountDownLatchTest {
private static CountDownLatch mainCountDown = new CountDownLatch(1);
// 6个运动员
private static CountDownLatch playerCountDown = new CountDownLatch(6);
public static void main(String[] args) throws InterruptedException {
ExecutorService executorService = Executors.newFixedThreadPool(6);
System.out.println("各就各位 预备");
for (int i = 0; i < 6; i++) {
executorService.execute(() ->{
System.out.println(Thread.currentThread().getName() + "运动员等待哨响");
// 确保所有运动员准备完毕
try {
Thread.sleep(3000);
//哨响,开始
mainCountDown.await();
System.out.println(Thread.currentThread().getName() + "运动员全力冲刺");
playerCountDown.countDown();
System.out.println(Thread.currentThread().getName() + "到达终点");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
//将executorService转换为ThreadPoolExecutor,ThreadPoolExecutor有方法 getActiveCount()可以得到当前活动线程数
int threadCount = ((ThreadPoolExecutor)executorService).getActiveCount();
if (threadCount == 6){
System.out.println("哨响");
mainCountDown.countDown();
//所有线程都到达终点
playerCountDown.await();
System.out.println("所有线程都到达终点,比赛结束");
}
executorService.shutdown();
}
}
CyclicBarrier
package com.tgdz.uap;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* ,假设6个线程就相当于6个运动员,到赛道起点时会报数进行统计,如果刚好是6的话,这一波就凑齐了,才能往下执行
*/
public class CyclicBarrierTest {
//指定必须有6个运动员到达后才能执行
private static CyclicBarrier cyclicBarrier = new CyclicBarrier(6,() -> {
System.out.println("所有运动员入场,裁判员一声令");
});
public static void main(String[] args) {
System.out.println("运动员准备进场,全场欢呼....");
ExecutorService executorService = Executors.newFixedThreadPool(6);
for (int i = 0; i < 6; i++) {
executorService.execute(() -> {
try {
System.out.println(Thread.currentThread().getName() + "运动员,进场");
cyclicBarrier.await();
System.out.println(Thread.currentThread().getName() + "运动员出发");
} catch (Exception e) {
e.printStackTrace();
}
});
}
}
}
CyclicBarrier 图解
CyclicBarrier在使用一次后,下面依然有效,可以继续当做计数器使用,这是与CountDownLatch的区别之一
CountDownLatch应用场景:假如有多个sheet,开启多个线程解析sheet等待所有线程解析完毕唤醒主线程响应解析完毕
CyclicBarrier应用场景:假如有多个sheet每sheet中保存不同厂家的年销售数据,开启多个线程解析sheet,解析完后再进行汇总处理