CountDownLatch详解-线程顺序控制

CountDownLatch详解-线程顺序控制

一、概念

1、countDownLatch是在java1.5被引入,存在于java.util.cucurrent包下。

2、countDownLatch这个类使一个线程等待其他线程各自执行完毕后再执行。

3、是通过一个计数器来实现的,计数器的初始值是线程的数量。每当一个线程执行完毕后,计数器的值就-1,当计数器的值为0时,表示所有线程都执行完毕,然后在闭锁上等待的线程就可以恢复工作了。

二、CountDownLatch 常用方法说明

CountDownLatch(int count); //构造方法,创建一个值为count 的计数器。

await();//阻塞当前线程,将当前线程加入阻塞队列。

await(long timeout, TimeUnit unit);//在timeout的时间之内阻塞当前线程,时间一过则当前线程可以执行,

countDown();//对计数器进行递减1操作,当计数器递减至0时,当前线程会去唤醒阻塞队列里的所有线程。

三、测试代码

业务场景:

统计用户数据、订单数和商品情况,然后统一处理返回结果。如果每个业务场景预计要5秒,单线程情况需要15秒左右,如果用多线程处理,费时5秒左右。在多线程情况下,如何保证多线程统一执行完毕并返回结果呢?

 private static Map<String,Object> map = new HashMap<>();
    //初始化计数器3
    private static  CountDownLatch countDownLatch = new CountDownLatch(3);
    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        System.out.println("开始时间:"+start);
        //统计新增用户
        Thread userThread = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println("线程一:统计新增用户开始");
                    Thread.sleep(5000);
                    map.put("newUser",10);
                    System.out.println("线程一:统计新增用户结束");
                    //计数器减一
                    countDownLatch.countDown();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        //统计订单
        Thread orderThread = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println("线程二:统计订单开始");
                    Thread.sleep(5000);
                    map.put("orderNum",20);
                    System.out.println("线程二:统计订单结束");
                    //计数器减一
                    countDownLatch.countDown();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        //统计商品
        Thread goodThread = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println("线程三:统计商品开始");
                    Thread.sleep(5000);
                    map.put("goodCount",100);
                    System.out.println("线程三:统计商品结束");
                    //计数器减一
                    countDownLatch.countDown();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        userThread.start();
        orderThread.start();
        goodThread.start();
        try {
            //主线程等待,countDownLatch为0的时候,也就是上面线程全都执行完毕,再执行下面的业务
            countDownLatch.await();
            System.out.println("统计完毕,统计结果:"+ JSON.toJSONString(map));
            long end = System.currentTimeMillis();
            System.out.println("结束时间:"+end+";耗时:"+(end-start));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

执行结果一

主线程会等到其他统计线程执行完毕以后才执行

开始时间:1601634626698
线程一:统计新增用户开始
线程二:统计订单开始
线程三:统计商品开始
线程二:统计订单结束
线程一:统计新增用户结束
线程三:统计商品结束
统计完毕,统计结果:{"goodCount":100,"newUser":10,"orderNum":20}
结束时间:1601634631811;耗时:5113

如果注释 countDownLatch.await();会有什么情况呢?

执行结果二

开始时间:1601634798801
线程一:统计新增用户开始
线程二:统计订单开始
线程三:统计商品开始
统计完毕,统计结果:{}
结束时间:1601634798957;耗时:156
线程一:统计新增用户结束
线程三:统计商品结束
线程二:统计订单结束

await()方法会让当前线程等待,只有countDownLatch的计数器为0时才会执行。如果因为程序异常计数器永远不为0,当前线程就会一会等待。可以考虑使用await(long timeout, TimeUnit unit);等待一段时间后执行。

使用场景:

A业务依赖B、C等业务处理完毕后再执行,可以考虑使用countDownLatch

关注公众号免费领取学习资料~

在这里插入图片描述

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
CountDownLatchJava中的一个同步工具类,它用于控制多个线程之间的执行顺序。CountDownLatch可以在一个或多个线程等待其他线程完成之前进行等待,直到所有线程都完成它才继续执行。 具体地说,CountDownLatch的使用场景一般是这样的:一个线程或多个线程需要等待其他线程完成某些操作之后才能执行,而其他线程完成操作之后需要通知等待的线程继续执行。这时就可以使用CountDownLatch来实现线程的顺序执行。 具体实现方式如下: 1. 创建一个CountDownLatch对象,设置计数器的初始值为等待的线程数。 2. 在等待的线程中调用CountDownLatch的await()方法进行等待,直到计数器值为0。 3. 在其他线程完成操作之后,调用CountDownLatchcountDown()方法将计数器的值减1,表示有一个线程完成操作。 4. 当计数器的值为0时,等待的线程就可以继续执行。 示例代码如下: ``` import java.util.concurrent.CountDownLatch; public class CountdownLatchExample { public static void main(String[] args) throws InterruptedException { CountDownLatch latch = new CountDownLatch(3); Thread t1 = new Thread(() -> { System.out.println("Thread 1 is running"); latch.countDown(); }); Thread t2 = new Thread(() -> { System.out.println("Thread 2 is running"); latch.countDown(); }); Thread t3 = new Thread(() -> { System.out.println("Thread 3 is running"); latch.countDown(); }); t1.start(); t2.start(); t3.start(); latch.await(); System.out.println("All threads have finished running"); } } ``` 在上述代码中,创建了一个CountDownLatch对象,计数器的初始值为3,表示需要等待3个线程完成操作。然后创建3个线程,每个线程完成操作之后都会调用countDown()方法将计数器的值减1。最后在主线程中调用await()方法进行等待,直到计数器的值为0,表示所有线程都已经完成操作。当计数器的值为0时,主线程就可以继续执行。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值