当前位置: 首页 > article >正文

Java 并发流程工具的实战探索

文章目录

    • 写在文章开头
    • CountDownLatch
      • 详解CountDownLatch工作流程
      • 模拟等待工作完成
      • 模拟运动员赛跑
      • 从源码角度分析CountDownLatch工作流程(补充aqs文章)
    • Semaphore
      • 详解Semaphore
      • 详解Semaphore工作原理
      • Semaphore使用注意事项
    • Condition
      • 详解Condition
      • 基于条件对象完成生产者、消费者模式
    • 详解CyclicBarrier
      • CyclicBarrier 原理和使用示例
      • CyclicBarrier 与CountDownLatch区别(重点)
    • 参考文献

写在文章开头

CountDownLatch

详解CountDownLatch工作流程

笔者一般称CountDownLatch为倒计时门闩,它主要用于需要某些条件下才能唤醒的需求场景,例如我们线程1必须等到线程2做完某些事,那么就可以设置一个CountDownLatch并将数值设置为1,一旦线程2完成业务逻辑后,将数值修改为0,此时线程1就会被唤醒:

在这里插入图片描述

模拟等待工作完成

通过上述的描述可能有点抽象,我们直接通过几个例子演示一下,我们现在有这样一个需求,希望等待5个线程完成之后,打印输出一句工作完成:

在这里插入图片描述

对应的代码示例如下,可以看到我们创建了数值为5的CountDownLatch ,一旦线程池里的线程完成工作后就调用countDown进行扣减,一旦数值变为0,主线程await就会放行,执行后续输出:

int workerSize = 5;
        CountDownLatch workCount = new CountDownLatch(workerSize);
        ExecutorService threadPool = Executors.newFixedThreadPool(workerSize);

        for (int i = 0; i < workerSize; i++) {
   
            final int workerNum = i;
            //5个工人输出完成工作后,扣减倒计时门闩数
            threadPool.submit(() -> {
   
                log.info("worker[{}]完成手头的工作", workerNum);
                workCount.countDown();
            });
        }

        try {
   
            //阻塞当前线程(主线程)往后走,只有倒计时门闩变为0之后才能继续后续逻辑
            log.info("等待worker工作完成");
            workCount.await();
        } catch (InterruptedException e) {
   
            log.info("倒计时门闩阻塞失败,失败原因[{}]", e.getMessage(), e);
        }

        threadPool.shutdown();
        while (!threadPool.isTerminated()) {
   

        }

        log.info("所有工人都完成手头的工作了");

对应的我们也给出输出结果,可以看到主线程在线程池线程完成后才输出:

在这里插入图片描述

模拟运动员赛跑

实际上CountDownLatch 可以让多个线程进行等待,我们不妨用线程模拟一下所有运动员就绪后,等待枪响后起跑的场景:

在这里插入图片描述

代码如下,每当运动员即线程池的线程准备就绪,则调用await等待枪响,一旦所有运动员就绪之后,主线程调用countDown模拟枪响,然后运动员起跑:

public static void main(String[] args) {
   
        log.info("百米跑比赛开始");

        int playerNum = 3;
        CountDownLatch gun = new CountDownLatch(1);
        ExecutorService threadPool = Executors.newFixedThreadPool(playerNum);
        
        for (int i = 0; i < playerNum; i++) {
   
            final int playNo = i;
            
            threadPool.submit(() -> {
   
                log.info("[{}]号运动员已就绪", playNo);
                try {
   
                    gun.await();
                } catch (InterruptedException e) {
   
                    log.info("[{}]号运动员线程阻塞失败,失败原因[{}]", playNo, e.getMessage(), e);
                }
                log.info("[{}]号运动员已经到达重点", playNo);
            });
        }

        //按下枪 所有运动员起跑
        gun.countDown();

        threadPool.shutdown();
        while 

http://www.kler.cn/a/450352.html

相关文章:

  • 无人设备遥控器之定向天线篇
  • Java中的访问修饰符:分类、作用及应用场景
  • 本科阶段最后一次竞赛Vlog——2024年智能车大赛智慧医疗组准备全过程——13使用Resnet-Bin
  • 【前端】入门指南:Vue中使用Node.js进行数据库CRUD操作的详细步骤
  • Spring Boot 中的 @Scheduled 定时任务以及开关控制
  • GitCode 光引计划投稿|MilvusPlus:开启向量数据库新篇章
  • 帧缓存的分配
  • shardingsphere分库分表项目实践3-分库分表算法原理
  • 并发编程(19)——引用计数型无锁栈
  • 【UI自动化】从WebDriver看Selenium与Appium的底层关联
  • 【python 逆向分析某有道翻译】分析有道翻译公开的密文内容,webpack类型,全程扣代码,最后实现接口调用翻译,仅供学习参考
  • SQL面试题——奖金瓜分问题
  • ChatGPT与Postman协作完成接口测试(一)
  • 处理字体图标、js、html及其他资源
  • 精读 84页华为BLM战略规划方法论
  • 概率论得学习和整理32: 用EXCEL描述正态分布,用δ求累计概率,以及已知概率求X的区间
  • css一道光闪过动效
  • 鸿蒙开发-ArkTS的ContainerSpan组件
  • 二进制部署k8s
  • Vite +Vue3打包生产环境去除项目中的console.log
  • Linux C/C++编程-线程退出时的清理机会
  • 易语言 OCR 文字识别
  • LightGBM分类算法在医疗数据挖掘中的深度探索与应用创新(上)
  • 数据结构-串-顺序结构实现
  • 如何使用vscode解决git冲突
  • 【微信小程序】微信小程序中的异步函数是如何实现同步功能的