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

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

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

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

class TestTask implements Runnable {
    private CountDownLatch latch;

    public CountDownLatch getLatch() {
        return latch;
    }

    public void setLatch(CountDownLatch latch) {
        this.latch = latch;
    }

    public TestTask(CountDownLatch latch) {
        this.latch = latch;
    }

    @Override
    public void run() {
        String threadName = Thread.currentThread().getName();
        try {
            Thread.sleep((long) (Math.random() * 10000));
            System.out.println("线程名:" + threadName + " 结束时间:" + DateUtils.getTime());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            latch.countDown();
        }
    }
}

5、完整示例代码

package com.ruoyi.demo.Executor;

import com.ruoyi.common.utils.DateUtils;

import java.util.concurrent.*;

public class CountDownLatchDemo {

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

}
class TestTask implements Runnable {
    private CountDownLatch latch;

    public CountDownLatch getLatch() {
        return latch;
    }

    public void setLatch(CountDownLatch latch) {
        this.latch = latch;
    }

    public TestTask(CountDownLatch latch) {
        this.latch = latch;
    }

    @Override
    public void run() {
        String threadName = Thread.currentThread().getName();
        try {
            Thread.sleep((long) (Math.random() * 10000));
            System.out.println("线程名:" + threadName + " 结束时间:" + DateUtils.getTime());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            latch.countDown();
        }
    }
}

6、执行效果

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

霸道流氓气质

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值