• Java中使用CountDownLatch实现并发流程控制


    场景

    CountDownLatch,它是 JDK 提供的并发流程控制的工具类,它是在 java.util.concurrent 包下,在 JDK1.5 之后加入的。

    应用场景举例:

    5个运动员参加马拉松比赛,好比五个线程,每个人跑完的时间不同,而比赛成绩统计必须要等待5个运动员都跑完才能往下进行。

    实现流程可以参考下图

     

    最开始 CountDownLatch 设置的初始值为 3,而后 T0 线程上来就调用 await 方法,它的做用是让这个线程开始等待,等待后面的 T一、T二、T3,它们每一次调用 countDown 方法,3 这个数值就会减 1,也就是从 3 减到 2,从 2 减到 1,从 1 减到 0,一旦减到 0 以后,这个 T0 就达到了本身触发继续运行的条件,因而它就恢复运行了。

    主要方法

    构造函数:

    public CountDownLatch(int count) {  };它的构造函数是传入一个参数,该参数 count 是须要倒数的数值。

    await():

    调用 await() 方法的线程开始等待,直到倒数结束,也就是 count 值为 0 的时候才会继续执行。

    await(long timeout, TimeUnit unit):

    await() 有一个重载的方法,里面会传入超时参数,这个方法的做用和 await() 相似,可是这里能够设置超时时间,

    若是超时就再也不等待了。

    countDown():

    把数值倒数 1,也就是将 count 值减 1,直到减为 0 时,以前等待的线程会被唤起。

    注:

    博客:
    霸道流氓气质的博客_CSDN博客-C#,架构之路,SpringBoot领域博主
    关注公众号
    霸道的程序猿
    获取编程相关电子书、教程推送与免费下载。

    实现

    1、使用ExecutorService搭建线程池

    Java中ExecutorService线程池的使用(Runnable和Callable多线程实现):

    Java中ExecutorService线程池的使用(Runnable和Callable多线程实现)_霸道流氓气质的博客-CSDN博客

    参考如上。

    2、然后新建countDownLatch,并设定计数器为5

    CountDownLatch countDownLatch = new CountDownLatch(5);

    这里的5与具体业务相关,比如这里模拟5个任务执行。

    3、在主进程中设置await

    1.     public static void main(String[] args) throws InterruptedException {
    2.         CountDownLatch countDownLatch = new CountDownLatch(5);
    3.         ExecutorService executorService = Executors.newFixedThreadPool(5);
    4.         for (int i = 0; i < 5; i++) {
    5.             executorService.submit(new TestTask(countDownLatch));
    6.         }
    7.         System.out.println("等待所有线程全部结束......");
    8.         countDownLatch.await();
    9.         System.out.println("线程全部结束");
    10.     }

    4、在任务执行类中通过构造方法传递countDownLatch,并在每个任务中通过随机数模拟不同任务的执行时间。

    在每个任务执行结束之后调用latch.countDown(),使计数器减1。

    1. class TestTask implements Runnable {
    2.     private CountDownLatch latch;
    3.     public CountDownLatch getLatch() {
    4.         return latch;
    5.     }
    6.     public void setLatch(CountDownLatch latch) {
    7.         this.latch = latch;
    8.     }
    9.     public TestTask(CountDownLatch latch) {
    10.         this.latch = latch;
    11.     }
    12.     @Override
    13.     public void run() {
    14.         String threadName = Thread.currentThread().getName();
    15.         try {
    16.             Thread.sleep((long) (Math.random() * 10000));
    17.             System.out.println("线程名:" + threadName + " 结束时间:" + DateUtils.getTime());
    18.         } catch (InterruptedException e) {
    19.             e.printStackTrace();
    20.         }finally {
    21.             latch.countDown();
    22.         }
    23.     }
    24. }

    5、完整示例代码

    1. package com.ruoyi.demo.Executor;
    2. import com.ruoyi.common.utils.DateUtils;
    3. import java.util.concurrent.*;
    4. public class CountDownLatchDemo {
    5.     public static void main(String[] args) throws InterruptedException {
    6.         CountDownLatch countDownLatch = new CountDownLatch(5);
    7.         ExecutorService executorService = Executors.newFixedThreadPool(5);
    8.         for (int i = 0; i < 5; i++) {
    9.             executorService.submit(new TestTask(countDownLatch));
    10.         }
    11.         System.out.println("等待所有线程全部结束......");
    12.         countDownLatch.await();
    13.         System.out.println("线程全部结束");
    14.     }
    15. }
    16. class TestTask implements Runnable {
    17.     private CountDownLatch latch;
    18.     public CountDownLatch getLatch() {
    19.         return latch;
    20.     }
    21.     public void setLatch(CountDownLatch latch) {
    22.         this.latch = latch;
    23.     }
    24.     public TestTask(CountDownLatch latch) {
    25.         this.latch = latch;
    26.     }
    27.     @Override
    28.     public void run() {
    29.         String threadName = Thread.currentThread().getName();
    30.         try {
    31.             Thread.sleep((long) (Math.random() * 10000));
    32.             System.out.println("线程名:" + threadName + " 结束时间:" + DateUtils.getTime());
    33.         } catch (InterruptedException e) {
    34.             e.printStackTrace();
    35.         }finally {
    36.             latch.countDown();
    37.         }
    38.     }
    39. }

    6、执行效果

     

  • 相关阅读:
    linux uboot制作自定义菜单指令menu
    安卓面经_anroid面经_111道安卓基础面试题全解析
    逆地理编码-离线版-part1
    电赛猜题?我觉得没用,还不如做好这些!
    C语言-静态通讯录(全功能)(详略版)
    AI模型训练参数
    Spring Security 核心解读(一)整体架构
    麒麟KYLINOS命令行设置系统静音
    javaI/O包中的包装模式
    Xray是什么
  • 原文地址:https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/126255413