CountDownLatch和CyclicBarrier的区别和应用场景

一、前言

在JDK的并发包里提供了几个非常有用的并发工具类。如线程等待的CountDownLatch和CyclicBarrier。

二、CountDownLatch

CountDownLatch允许一个或多个线程等待其他线程完成操作后再执行后续的代码。

2.1 应用场景

  • 1个线程等多个线程:当程序需要从3个接口获取数据的时候,可以同时开3个线程去获取数据,等数据都获取到了,主线程再进行下一步操作。
  • 1个线程等多个线程:解析Excel的多个shell页,可以开多个线程去读取。
  • 多个线程等待:如秒杀场景同时让一组数据同时等待,同时恢复。

2.2 解析Excel的Shell页代码

2.2.1 主要的方法

countDown(): 将CountDownLatch对象内部维护的state变量减1。

wait() :等待CountDownLatch对象内部维护的state变量减为0之后再往下执行代码。

public void getShellData(){
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(51010, TimeUnit.MINUTES, new ArrayBlockingQueue<>(5));
        CountDownLatch latch = new CountDownLatch(5);
        List<ShellData> shellDataList = new ArrayList<>();
        for (int i = 0; i < 5; i++) {
            int finalI = i;
            threadPoolExecutor.execute(()->{
                shellDataList.add(getShellData(finalI));
                latch.countDown();
            });
        }
        latch.wait();
        // 5个shell页的数据都获取完了,再对汇总后的数据进行处理
        doOtherByShellDataList(shellDataList);
    }

2.3 死锁问题

如果线程池中线程的数量较少,在高并发时会出现多个请求占用了全部的线程,但是每个请求又需要await其他线程,被等待的线程拿不到线程资源无法执行,导致多个请求同时进入线程阻塞,最后形成死锁。

2.3.1 解决方式

使用自定义线程池,请求队列控制数量,等待加上超时时间,使用拒绝策略。

三、同步屏障CyclicBarrier

CyclicBarrier的字面意思是可循环使用(Cyclic)的屏障(Barrier)。它要做的事情是,让所有的线程都到达屏障(同步点)的时候,屏障才会打开,所有的线程才会往下执行。

3.1 应用场景

  • 玩排位的时候,会等待10个游戏玩家都准备好了之后才会开始游戏。
  • 朋友聚会的时候,会等待所有人都到齐了才会开始吃饭。
  • 闯关游戏,所有玩家都完成当前关卡后再一起去下一关。

3.2 排位代码

3.2.1 主要的方法

await() :将当前线程阻塞,等到所有的线程都到达屏障后一起执行。
reset() :将屏障重置为初始状态之后就可以复用。
isBroken() : 方法检测Barrier是否被破坏。
public static void main(String[] args) throws BrokenBarrierException, InterruptedException {
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(51010, TimeUnit.MINUTES, new ArrayBlockingQueue<>(5));
        CyclicBarrier barrier = new CyclicBarrier(5);
        for (int i = 0; i < 5; i++) {
            threadPoolExecutor.execute(()->{
                try {
                    Thread.sleep(Math.round(1000));
                    System.out.println(Thread.currentThread().getName() + ": 玩家准备完成。");
                    barrier.await();
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }
            });
        }
        barrier.await();
        System.out.println("玩家全部准备完成!开始游戏。");
        threadPoolExecutor.shutdown();
    }


pool-1-thread-3: 玩家准备完成。
pool-1-thread-1: 玩家准备完成。
pool-1-thread-2: 玩家准备完成。
pool-1-thread-4: 玩家准备完成。
pool-1-thread-5: 玩家准备完成。
玩家全部准备完成!开始游戏。

四、二者的区别

  • CountDownLatch的计数器只能使用一次。而CyclicBarrier的计数器可以使用reset() 方法重置,强调循环。
  • CyclicBarrier能处理更为复杂的业务场景,比如计算发生错误,可以结束阻塞,重置计数器,重新执行程序。
  • CyclicBarrier还提供getNumberWaiting(可以获得CyclicBarrier阻塞的线程数量)、isBroken(用来知道阻塞的线程是否被中断)等方法。
  • CountDownLatch会阻塞主线程,CyclicBarrier不会阻塞主线程,只会阻塞子线程。

原文始发于微信公众号(程序员欢月):CountDownLatch和CyclicBarrier的区别和应用场景

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由半码博客整理,本文链接:https://www.bmabk.com/index.php/post/61247.html

(0)

相关推荐

  • 【第八篇】SpringSecurity核心过滤器-CsrfFilter

    springSecurity核心过滤器-CsrfFilter 在这里插入图片描述   Spring Security除了认证授权外功能外,还提供了安全防护功能。本文我们来介绍下Sp…

    2022年11月28日
    09
  • SpringBoot项目traceId生成/日志打印

    参考文章 : W3C_0101博文链接 前言 查看服务日志时,当服务被调过于频繁,日志刷新太快,会影响到联调、测试、线上问题的排查效率,能不能为每一个请求的日志打一个唯一标识呢?后…

    2022年12月30日
    07
  • 享元模式

    设计模式系列往期精彩文章 设计模式七大原则 单例模式 工厂模式 原型模式 建造者模式 适配器模式 桥接模式 装饰者模式 组合模式 外观模式 无场景不设计有这样的一个项目需求:给客户…

    2023年1月18日
    042
  • 教你自己制作一个ALU(上)

    「计算机在没有齿轮的时候是如何负责运算的呢?」 「ALU就是计算机里负责运算的组件,这篇文章就是教你自己做一个ALU」 第一个ALU 「1970年,第一个封装在单个芯片内的完整AL…

    2023年1月15日
    00
  • MyBatis 缓存工作原理

    荐言 大家好,我是连边。 看这篇文章之前,要上厕所的去上厕所,准备好瓜子与板凳。 因为文章是那种看了停不下来,但是又确实很长 … 面试的时候,就会直接问你:“了解Myb…

    2022年12月14日
    05
  • ElasticSearch进阶篇之搞定在SpringBoot项目中的实战应用

    在这里插入图片描述 1.ES 的java API两种方式   ElasticSearch 的API 分为 REST Client API(http请求形式)以及 transport…

    2022年11月28日
    030
  • Flowable事件-定时器事件

    在这里插入图片描述 Flowable事件   事件(event)通常用于为流程生命周期中发生的事情建模。事件总是图形化为圆圈。在BPMN 2.0中,有两种主要的事件分类:捕获(ca…

    2022年11月28日
    031
  • 优秀后端都应该具备的开发好习惯

    前言 大家好,我是连边。 这篇文章记录了一个优秀的后端开发程序员,应该有哪些好的开发习惯。 1.注释尽可能全面,写有意义的注释 接口方法、类、复杂的业务逻辑,都应该添加有意义的注释…

    2022年12月14日
    08
  • Spring Bean的生命周期

    Bean的生命周期 过程 : bean创建 -> bean初始化 -> 销毁 对象的构造 单例模式:在容器启动的时候创建对象; 多例模式:在每次获取的时候创建对象; 初…

    2022年12月30日
    02
  • 仅此一招,再无消息乱序的烦恼

    1. 概览 RocketMQ 早已提供了一组最佳实践,但工作在一线的伙伴却很少知道,项目中的各种随性代码经常导致消息错乱问题,严重影响业务的准确性。为了保障最佳实践的落地,降低一线…

    2022年12月5日
    08
分享本页
返回顶部