阿里云开发者社区

电脑版
提示:原网页已由神马搜索转码, 内容由developer.aliyun.com提供.

CountDownLatch 实战

2024-05-07123
版权
版权声明:
本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《 阿里云开发者社区用户服务协议》和 《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写 侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。
简介:CountDownLatch 实战

CountDownLatch 是一个同步辅助工具,它允许一个或多个线程等待其他线程完成一系列操作。以下是一个 CountDownLatch 的实战示例,展示了如何使用它来协调多个线程的执行顺序。

CountDownLatch的主要功能是,它有一个计数器,初始值为一个非负整数。当计数器的值减为0时,所有等待的线程才会继续执行。

原理

CountDownLatch是一个同步协助类,它允许一个或多个线程等待,直到其他线程完成操作集。它使用给定的计数值(count)初始化,通过调用await方法,线程会进入等待状态,直到计数值由于countDown方法的调用达到0,此时所有等待的线程才会被释放,继续执行后续操作。

CountDownLatch的实现原理是基于锁和计数器。它使用一个内部锁来控制对计数器的访问,同时维护一个计数器来记录给定的计数值。初始化时,计数器的值等于给定的计数值。每次调用countDown方法时,计数器会减1,而每次调用await方法时,计数器会加1。当计数器的值为0时,表示所有线程都已完成操作,await方法会释放锁并返回。

由于CountDownLatch是基于锁和计数器实现的,因此它具有线程安全性。同时,它也支持多个线程之间的协作和同步,使得线程可以等待其他线程完成操作,这对于并发编程来说非常有用。

使用

CountDownLatch的常用方法有:

CountDownLatch(int count): 创建一个计数器,初始值为给定的非负整数count。

void await() throws InterruptedException: 使当前线程等待,直到计数器减为0或者当前线程被中断。

boolean await(long timeout, TimeUnit unit) throws InterruptedException: 使当前线程等待,直到计数器减为0,或者当前线程被中断,或者等待时间超过指定的timeout。

void countDown(): 计数器减1。

CountDownLatch的使用场景包括:

等待一组线程执行完毕:通过初始化一个计数器,等待指定数量的任务完成后再执行后续任务。

实现一个线程释放一组线程的功能:通过一个计数器来控制多个线程的执行顺序,当计数器减到0时,所有线程继续执行。

多个线程释放多个线程的场景:通过CountDownLatch可以控制多个线程的执行顺序,从而实现多个线程的协调和同步。

使用CountDownLatch时需要注意以下几点:

CountDownLatch不能被重复使用,一旦计数器减到0,就不能再被await()了。

如果等待的线程被中断,CountDownLatch不会抛出异常,而是会抛出InterruptedException。

如果在指定的超时时间内,计数器没有减到0,await()方法会返回false。

总之,CountDownLatch是一个非常实用的同步工具类,可以用于实现多线程的协调和同步。

例子

假设我们有一个程序,其中有两个线程需要按照一定的顺序执行:线程 A 需要在所有线程 B 之前执行完毕。我们可以使用 CountDownLatch 来实现这个顺序。

import java.util.concurrent.CountDownLatch;    public class CountDownLatchExample {        public static void main(String[] args) throws InterruptedException {          CountDownLatch latch = new CountDownLatch(5);            // 创建并启动线程 B          for (int i = 0; i < 5; i++) {              new Thread(() -> {                  try {                      System.out.println("线程B开始执行...");                      Thread.sleep(1000); // 模拟线程B的执行时间                      System.out.println("线程B执行完毕...");                  } catch (InterruptedException e) {                      e.printStackTrace();                  } finally {                      latch.countDown(); // 减少计数                  }              }).start();          }            // 等待所有线程 B 执行完毕          latch.await();            // 创建并启动线程 A          new Thread(() -> {              System.out.println("线程A开始执行...");              // 模拟线程A的执行时间              try {                  Thread.sleep(3000);              } catch (InterruptedException e) {                  e.printStackTrace();              }              System.out.println("线程A执行完毕...");          }).start();      }  }

在上述代码中,我们首先创建了一个 CountDownLatch 对象,并指定初始计数值为 5。然后,我们创建了 5 个线程 B,每个线程在执行完成后会调用 countDown() 方法减少计数器的值。接着,我们使用latch.await() 方法等待所有线程 B 执行完毕。最后,我们创建了一个线程 A,该线程在所有线程 B 执行完毕后开始执行。

通过使用 CountDownLatch,我们可以确保线程 A 只在所有线程 B 执行完毕后才开始执行,实现了线程之间的顺序控制。

实战代码

ExecutorService executorService  = newFixedThreadPool(3);        CountDownLatch countDownLatch = new CountDownLatch(3);        List<TestDefectUpdateVo> listNo=new ArrayList<>();        List<TestDefectUpdateVo> testDefectUpdateVos=new ArrayList<>();        List<TestDefectUpdateVo> testDefectUpdateVosDic=new ArrayList<>();        executorService.submit(()->{            List<TestDefectUpdateVo> testList = testDefectMapper.selectProjectNum(leafProjectId, null);            listNo.addAll(testList);            countDownLatch.countDown();        }).get();        executorService.submit(()->{            List<TestDefectUpdateVo> testDefect = testDefectMapper.selectProjectAllNum(leafProjectId);            testDefectUpdateVos.addAll(testDefect);            countDownLatch.countDown();        }).get();        executorService.submit(()->{            List<TestDefectUpdateVo> testDefectUpdate = testDefectMapper.selectProjectDicNum(leafProjectId);            testDefectUpdateVosDic.addAll(testDefectUpdate);            countDownLatch.countDown();        }).get();
        countDownLatch.await(5, TimeUnit.SECONDS);


目录
相关文章
Element UI - el-scrollbar 如何隐藏横向滚动条?
Element UI - el-scrollbar 如何隐藏横向滚动条?
80300
|
人工智能API决策智能
MetaGPT( The Multi-Agent Framework):颠覆AI开发的革命性多智能体元编程框架
MetaGPT( The Multi-Agent Framework):颠覆AI开发的革命性多智能体元编程框架
MetaGPT( The Multi-Agent Framework):颠覆AI开发的革命性多智能体元编程框架
|
自然语言处理算法机器人
PaddleNLP通用信息抽取技术UIE【一】产业应用实例:信息抽取{实体关系抽取、中文分词、精准实体标。情感分析等}、文本纠错、问答系统、闲聊机器人、定制训练
PaddleNLP通用信息抽取技术UIE【一】产业应用实例:信息抽取{实体关系抽取、中文分词、精准实体标。情感分析等}、文本纠错、问答系统、闲聊机器人、定制训练
PaddleNLP通用信息抽取技术UIE【一】产业应用实例:信息抽取{实体关系抽取、中文分词、精准实体标。情感分析等}、文本纠错、问答系统、闲聊机器人、定制训练
|
8月前
|
人工智能自然语言处理
WebDreamer:基于大语言模型模拟网页交互增强网络规划能力的框架
WebDreamer是一个基于大型语言模型(LLMs)的网络智能体框架,通过模拟网页交互来增强网络规划能力。它利用GPT-4o作为世界模型,预测用户行为及其结果,优化决策过程,提高性能和安全性。WebDreamer的核心在于“做梦”概念,即在实际采取行动前,用LLM预测每个可能步骤的结果,并选择最有可能实现目标的行动。
18511
WebDreamer:基于大语言模型模拟网页交互增强网络规划能力的框架
Python基础第八篇(Python异常处理,模块与包)
Python基础第八篇(Python异常处理,模块与包)
|
9月前
|
C#开发工具Windows
C# 获取Windows系统信息以及CPU、内存和磁盘使用情况
C# 获取Windows系统信息以及CPU、内存和磁盘使用情况
22300
|
8月前
|
缓存监控Java
如何运用JAVA开发API接口?
本文详细介绍了如何使用Java开发API接口,涵盖创建、实现、测试和部署接口的关键步骤。同时,讨论了接口的安全性设计和设计原则,帮助开发者构建高效、安全、易于维护的API接口。
65144
|
9月前
|
Android开发
Android面试之Activity启动流程简述
Android面试之Activity启动流程简述
18166
|
11月前
Mac卸载 Node npm,升级 Node
Mac卸载 Node npm,升级 Node
17100
|
存储缓存NoSQL
Redis入门到通关之解决Redis缓存一致性问题
Redis入门到通关之解决Redis缓存一致性问题

热门文章

最新文章

  • 1
    DataWorks+Hologres:打造企业级实时数仓与高效OLAP分析平台
    22
  • 2
    基于YOLOv8的FPS射击类游戏人物识别项目|完整源码数据集+PyQt5界面+完整训练流程+开箱即用!
    22
  • 3
    豆蔻妇科大模型再突破:钉钉行业训练平台+精标数据SFT ,准确率从 77.1%上升至 90.2%
    26
  • 4
    如何开发ERP系统中的计划管理板块(附架构图+流程图+代码参考)
    25
  • 5
    关于大模型的一些知识
    20
  • 6
    金属材料表面六种缺陷类型数据集 | 适用于YOLO等视觉检测模型(1800张图片已划分、已标注)
    16
  • 7
    Windows IIS 10如何配置自签名SSL并实现自动跳转
    17
  • 8
    看不见就管不好?——机器学习如何把供应链“照亮”!
    24
  • 9
    数据不止防故障,还能防攻击?
    14
  • 10
    城市早高峰太难了?其实你堵的是数据不是车!
    16