CountDownLatch与CyclicBarrier的比较应用
CountDownLatch与CyclicBarrier的比较&应用
CountDownLatch
说明
一个线程等待其他线程执行完之后再执行,相当于加强版的join,在初始化CountDownLatch是需要设定计数器的数值(计数器数据不一定跟线程数相同,但是一定计数器的值一定是要大于等于线程数,一个线程中可以进行多次扣减。当计数器扣减至0时才可继续向下执行)
示例代码
@Slf4j
public class TestCountDownLatch {public static CountDownLatch countDownLatch = new CountDownLatch(5);public static void main(String[] args) throws InterruptedException {ExecutorService executorService = Executors.newCachedThreadPool();for (int i = 0; i < 5; i++) {executorService.execute(TestCountDownLatch::doTasK);}countDownLatch.await();log.info("所有线程执行完毕,开始执行主线程");}private static void doTasK() {try {log.info("线程{}开始准备", Thread.currentThread().getName());Thread.sleep(RandomUtil.randomLong(1000, 3000));countDownLatch.countDown();log.info("线程{}准备完毕", Thread.currentThread().getName());} catch (InterruptedException e) {Thread.currentThread().interrupt();} catch (Exception e) {e.printStackTrace();}}
}
结果
21:44:07.747 [pool-1-thread-1] INFO com.huakai.springenv.juc.TestCountDownLatch - 线程pool-1-thread-1开始准备
21:44:07.747 [pool-1-thread-5] INFO com.huakai.springenv.juc.TestCountDownLatch - 线程pool-1-thread-5开始准备
21:44:07.747 [pool-1-thread-2] INFO com.huakai.springenv.juc.TestCountDownLatch - 线程pool-1-thread-2开始准备
21:44:07.747 [pool-1-thread-3] INFO com.huakai.springenv.juc.TestCountDownLatch - 线程pool-1-thread-3开始准备
21:44:07.747 [pool-1-thread-4] INFO com.huakai.springenv.juc.TestCountDownLatch - 线程pool-1-thread-4开始准备
21:44:08.878 [pool-1-thread-4] INFO com.huakai.springenv.juc.TestCountDownLatch - 线程pool-1-thread-4准备完毕
21:44:08.887 [pool-1-thread-1] INFO com.huakai.springenv.juc.TestCountDownLatch - 线程pool-1-thread-1准备完毕
21:44:09.464 [pool-1-thread-3] INFO com.huakai.springenv.juc.TestCountDownLatch - 线程pool-1-thread-3准备完毕
21:44:10.017 [pool-1-thread-5] INFO com.huakai.springenv.juc.TestCountDownLatch - 线程pool-1-thread-5准备完毕
21:44:10.633 [pool-1-thread-2] INFO com.huakai.springenv.juc.TestCountDownLatch - 线程pool-1-thread-2准备完毕
21:44:10.633 [main] INFO com.huakai.springenv.juc.TestCountDownLatch - 所有线程执行完毕,开始执行主线程
应用场景
- 一个操作依赖多个前置操作的完成(为了提高效率,前置操作使用多线程执行)才能开始执行
- 比如计算用户任务的完成情况,任务的完成情况依赖于不同需要外部接口,这里执行多线程执行外部接口的调用,等待所所有调用完成后开始计算用户的任务完成情况
Cyclicbarrier
说明
让一组线程到达某个屏障,然后被阻塞,一直到最后一个线程到达屏障,然后所有屏障开放,所有被阻塞的线程继续执行,计数器与线程数相等。
示例代码
@Slf4j
public class TestCycleBarrier {private static CyclicBarrier cyclicBarrier = new CyclicBarrier(5,()->log.info("所有线程已经准备完毕"));public static void main(String[] args) {ExecutorService executorService = Executors.newCachedThreadPool();for (int i = 0; i < 5; i++) {executorService.execute(TestCycleBarrier::doTasK);}}private static void doTasK() {try {log.info("线程{}开始准备",Thread.currentThread().getName());Thread.sleep(RandomUtil.randomLong(1000,3000));cyclicBarrier.await();log.info("线程{}开始执行",Thread.currentThread().getName());} catch (InterruptedException e) {Thread.currentThread().interrupt();}catch (Exception e) {e.printStackTrace();}}
}
结果
21:47:05.762 [pool-1-thread-1] INFO com.huakai.springenv.juc.TestCycleBarrier - 线程pool-1-thread-1开始准备
21:47:05.762 [pool-1-thread-2] INFO com.huakai.springenv.juc.TestCycleBarrier - 线程pool-1-thread-2开始准备
21:47:05.762 [pool-1-thread-4] INFO com.huakai.springenv.juc.TestCycleBarrier - 线程pool-1-thread-4开始准备
21:47:05.762 [pool-1-thread-5] INFO com.huakai.springenv.juc.TestCycleBarrier - 线程pool-1-thread-5开始准备
21:47:05.762 [pool-1-thread-3] INFO com.huakai.springenv.juc.TestCycleBarrier - 线程pool-1-thread-3开始准备
21:47:08.383 [pool-1-thread-3] INFO com.huakai.springenv.juc.TestCycleBarrier - 所有线程已经准备完毕
21:47:08.383 [pool-1-thread-1] INFO com.huakai.springenv.juc.TestCycleBarrier - 线程pool-1-thread-1开始执行
21:47:08.383 [pool-1-thread-5] INFO com.huakai.springenv.juc.TestCycleBarrier - 线程pool-1-thread-5开始执行
21:47:08.383 [pool-1-thread-4] INFO com.huakai.springenv.juc.TestCycleBarrier - 线程pool-1-thread-4开始执行
21:47:08.383 [pool-1-thread-2] INFO com.huakai.springenv.juc.TestCycleBarrier - 线程pool-1-thread-2开始执行
21:47:08.383 [pool-1-thread-3] INFO com.huakai.springenv.juc.TestCycleBarrier - 线程pool-1-thread-3开始执行
应用场景
- 一组操作需要分为多步(为了提高效率,每一步的任务都拆成了子任务并行执行)完成,每一步操作必须等待所有的上一步操作的完成
- 在数据分析的流程中,分为数据清洗和数据分析,数据因为量比较大,清洗和分析都分为了多个任务执行,但在执行任务分析之前,必须保证所有的数据都完成清洗