Java 入门指南:Java 并发编程 —— 同步工具类 CyclicBarrier(循环屏障)

news/2024/10/11 19:04:39/文章来源:https://blog.csdn.net/Zachyy/article/details/142151648

文章目录

    • 同步工具类
    • CyclicBarrier
      • 构造函数
      • 常用方法
      • 工作机制
      • 使用步骤
      • 适用场景
      • CyclicBarrier与CountDownLatch的区别
      • 示例代码

同步工具类

JUC(Java.util.concurrent)是 Java 提供的用于并发编程的工具类库,其中包含了一些通信工具类,用于在多个线程之间进行协调和通信,特别是在多线程和网络通信方面。这些工具类提供了丰富的功能,帮助开发者高效地实现复杂的并发控制和网络通信需求。

![[JUC Communication Utilities.png]]

CyclicBarrier

CyclicBarrier(循环屏障)是 Java 中的一种同步辅助类,用于控制多个线程在某个屏障点上等待,然后在达到屏障点时一起继续执行。它允许一组线程互相等待,直到所有线程都达到某个公共屏障点(也称为同步点),然后这些线程才会一起继续执行后续的任务。与 CountDownLatch 类似,但可以重复使用

CyclicBarrier 通过一个计数器来实现,计数器初始值可以设定为一个正整数,当调用 await() 方法的线程数量达到指定值时,所有线程会被释放并继续执行。同时,CyclicBarrier 的计数器会重置为初始值,以便下一轮的等待。

构造函数

CyclicBarrier 提供了两个构造函数:

  1. 创建一个新的 CyclicBarrier,它将等待给定数量的线程(即 parties 参数指定的数量)到达屏障点,然后这些线程才会继续执行。
CyclicBarrier(int parties)
  1. 另一个构造函数除了指定需要等待的线程数量外,还允许指定一个当所有线程都到达屏障点时执行的任务(即barrierAction)。这个任务在所有线程被释放之前执行,可以用于进行某些准备工作或汇总工作。
CyclicBarrier(int parties, Runnable barrierAction)

常用方法

  • await():这是主要的等待方法,当所有线程都调用此方法时,所有线程都会被释放继续执行。该方法有两个重载版本:

    • await():等待所有线程,没有超时限制。
    • await(long timeout, TimeUnit unit):等待所有线程,有超时限制。
  • getParties():返回设置屏障时指定的线程数。

  • isBroken():如果屏障因为中断或超时而失效,则返回 true

  • reset():重置屏障,使其可以再次使用。

  • awaitingThreadCount():返回当前正在等待屏障的线程数。

工作机制

  1. 线程阻塞:当线程调用 CyclicBarrierawait() 方法时,如果未达到屏障点(即未达到指定的线程数量),则该线程将被阻塞,直到所有线程都调用 await() 方法并到达屏障点。

  2. 计数器减一:每当一个线程调用 await() 方法时,CyclicBarrier 内部的计数器会减一。当计数器减至零时,表示所有线程都已到达屏障点。

  3. 执行屏障任务(可选):如果构造函数中指定了屏障任务(barrierAction),则在所有线程都到达屏障点后,该任务将被执行。

  4. 线程唤醒:执行完屏障任务(如果有的话)后,所有在屏障点等待的线程都将被唤醒,并继续执行后续的任务。

  5. 重置计数器:在释放所有线程后,CyclicBarrier 的计数器可以被重置,以便下一次使用。如果需要重置计数器,可以调用 reset() 方法。

使用步骤

使用 CyclicBarrier 的基本步骤如下:

  1. 创建一个 CyclicBarrier 对象,并指定参与线程的数量。

  2. 在每个参与线程中,调用 await() 方法,表示线程到达屏障点,等待其他线程到达。

  3. 当指定数量的线程都调用了 await() 方法后,所有线程会被释放,可以继续执行后续操作。

CyclicBarrier 非常灵活,并且可以自定义屏障动作,可以在所有线程到达屏障点触发之前或之后执行一些特定的操作。

CyclicBarrier参与线程数量必须大于等于 2,否则无论怎样调用await() 方法,都会导致线程阻塞。另外,CyclicBarrier 是一次性的,但一旦所有线程被释放,计数器会重置为初始值,可以进行下一轮的等待。

CyclicBarrier 在多线程协调和同步的场景中非常有用,可以控制线程的执行顺序和等待状态,提高并发性能和效率。

适用场景

CyclicBarrier 的使用场景通常是多个线程需要相互等待,直到所有线程都到达某个屏障点,然后再一起开始执行后续操作。常见的应用场景有:

  1. 将一个大任务拆分成多个子任务,多个线程并发执行这些子任务,最后等待所有子任务完成后再汇总结果。

  2. 执行多个并发测试用例,所有测试用例需要同时开始执行,在一个屏障点等待并打开屏障,然后进行下一次测试。

CyclicBarrier与CountDownLatch的区别

虽然 CyclicBarrier 和 CountDownLatch(倒计时门闩) 都可以用来实现线程间的同步,但它们之间存在一些关键的区别:

  1. 计数器重置CountDownLatch 的计数器只能使用一次,一旦计数器减为零,就不能再被重置。而 CyclicBarrier 的计数器可以通过调用reset()方法来重置,以便重复使用。

  2. 使用场景CountDownLatch 主要用于一组线程等待另一组线程完成某项操作,而 CyclicBarrier 则主要用于一组线程互相等待,直到所有线程都达到某个同步点后再一起继续执行。

  3. 异常处理:当 CyclicBarrier 的屏障被破坏时(例如,由于某个线程在等待时被中断或超时),它会抛出 BrokenBarrierException 异常。而 CountDownLatch 则没有类似的异常处理机制。

示例代码

让我们通过一个具体的例子来展示 CyclicBarrier 的使用。

我们将模拟一个场景:一群登山者计划一起出发去攀登一座山。但是,他们约定在一个集合点汇合,只有当所有人都到齐了,他们才会开始攀登。如果有人提前到达,他们会等待其他人。如果有登山者因为某种原因无法到达集合点(如被中断或超时未到),那么整个队伍的计划就会取消。

import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class ClimbersExample {public static void main(String[] args) throws InterruptedException {int numberOfClimbers = 5;CyclicBarrier barrier = new CyclicBarrier(numberOfClimbers, () -> {System.out.println("所有登山者已经集合完毕,开始攀登!");});ExecutorService executor = Executors.newFixedThreadPool(numberOfClimbers);for (int i = 0; i < numberOfClimbers; i++) {final int climberNumber = i + 1;executor.submit(() -> {try {System.out.println("登山者 " + climberNumber + " 正在前往集合点...");Thread.sleep((long) (Math.random() * 5000)); // 模拟不同的准备时间System.out.println("登山者 " + climberNumber + " 到达集合点");barrier.await(); // 等待所有登山者} catch (InterruptedException | BrokenBarrierException e) {System.err.println("登山者 " + climberNumber + " 无法到达集合点: " + e.getMessage());}});}executor.shutdown();}
}

示例说明:

  1. 初始化 CyclicBarrier:我们创建了一个 CyclicBarrier,指定了参与的登山者数量为5,并且当所有登山者都到达集合点时,会执行一个 Runnable 任务,输出信息表示登山活动可以开始。

  2. 创建线程池:我们创建了一个固定大小的线程池来模拟5位登山者的行动。

  3. 提交任务:每个登山者都有自己的任务,模拟他们准备的时间不同,到达集合点的时间也不同。

  4. 等待所有登山者:每个登山者到达集合点后,会调用 barrier.await() 方法,等待其他登山者。只有当所有登山者都到达集合点后,才会继续执行后续的操作。

  5. 处理异常:如果某个登山者被中断或者因为其他原因无法到达集合点,会捕获异常并打印相关信息。

  6. 关闭线程池:最后,我们关闭线程池,确保资源得到释放。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ldbm.cn/p/441263.html

如若内容造成侵权/违法违规/事实不符,请联系编程新知网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

NLP-文本分类文献阅读-前置基础-词汇解释-通俗易懂-9月份-学习总结

目录 迁移学习 特征选择 特征工程 朴素贝叶斯分类方法 支持向量机 K-最近邻&#xff08;K-Nearest Neighbors, KNN&#xff09; 特征向量稀疏 卷积神经网络 循环神经网络 图神经网络 TextCNN 动态 K 最大池化 One-hot BOW Word2vec 池化&#xff08;Pooling&#xff09; 全连接…

windows和linux安装mysql5.7.31保姆级教程

一&#xff0c;资源如下&#xff0c;里面有windows和linux版的安装软件&#xff0c;内含Visual C2013中文版windows系统插件 windows资源地址&#xff1a;https://download.csdn.net/download/l1o3v1e4ding/89725150 linux&#xff08;centos&#xff09;资源地址&#xff1a;…

AI电商,如何提高设计效率?

第一步&#xff1a;找参考 第二步&#xff1a;提取关键词 我用的文心一言 第三步&#xff1a;选择AI绘画工具&#xff08;千鹿 设计助手&#xff09; 千鹿设计助手——FLux文生图&#xff0c;你也可以选择你手上的AI绘画工具 这个新用户注册会赠送1000积分 第四步生图

【BIO、NIO、AIO适用场景分析】

BIO、NIO、AIO适用场景分析 1.适用场景&#xff1a;2.BIO基本介绍2.1 BIO示例 3.Java NIO基本介绍3.1 NIO中三个核心部分&#xff1a;3.2 NIO非阻塞3.3 buffer案例3.4 比较 1.适用场景&#xff1a; BIO方式适用于连接数目比较少且固定的架构&#xff0c;这种方式对服务器资源要…

qt绘制时钟

代码 #include "widget.h" #include "ui_widget.h"#include <QWidget> #include <QPaintEvent> //绘图事件 #include <QDebug> //测试 #include <QPainter> //画家 #include <QPen> //笔 #include <QBrush> //画刷 …

从零到一,数字文创IP是如何在基地中孵化成长的?

在数字时代的浪潮下&#xff0c;数字文创IP孵化基地正成为培育创新的肥沃土壤&#xff0c;见证着一个个数字文创 IP 从无到有、茁壮成长。 数字文创IP孵化基地首先为创意的萌发提供了空间。这里汇聚了各路富有创造力的人才&#xff0c;他们的思想在这里碰撞&#xff0c;灵感的火…

【Lua学习】Lua最最基础的

Lua是什么&#xff1f; Lua是一种强大、高效、轻量级、可嵌入的脚本语言。它支持过程式编程、面向对象编程、函数式编程、数据驱动编程和数据描述。 Lua将简单的过程式语法与基于关联数组和可扩展语义的强大数据描述构造相结合。Lua是动态类型的&#xff0c;通过基于寄存器的虚…

金色传说:SAP-MM-物料主数据增强:MM01增强自定义字段+自定义字段添加到IDoc发送给ME系统增强,一文写完,纯干货,全宇宙最详细!

文章目录 需求场景整体实现流程步骤一:MM01屏幕增强步骤二:MM01/MM02保存增强步骤三:IDoc增强发送自定义字段步骤四:做发送测试小结需求场景 1.MM01物料主数据-基本数据2中的行业标准字段只有18位长度,不满足用户需求,MM01创建物料主数据保存时需要增强自定义字段. 2.执行标准…

卷积神经网络(一)

目录 一.卷积神经网络的组成 二.卷积层 目的&#xff1a; 参数&#xff1a; 计算公式 卷积运算过程 三.padding-零填充 1.Valid and Same卷积 2.奇数维度的过滤器 四.stride步长 五.多通道卷积 1.多卷积核(多个Filter) 六.卷积总结 七.池化层(Pooling) 八.全连接层…

2013年

B D B C D 分支结点是非叶结点 B 47 C A C C D D C A C

docker mysql 容器导入数据 .sql文件导入容器

docker mysql 容器导入数据 前言准备工作1、按需准备sql文件2、将文件上传服务器&#xff08;宿主机&#xff09;3、将sql文件复制进容器中 操作步骤1、进入容器内部2、进入数据库3、创建数据库4、切换数据库5、导入sql文件 前言 本文所涉及应用场景&#xff1a;远程部署环境…

使用 Elementary 实现开源数据可观测性 — 从零到精通(第一部分)

欢迎来到雲闪世界。我希望在我还是初学者时能有一份循序渐进的实践指南 数据可观测性及其重要性经常被讨论和撰写为现代数据和分析工程的一个重要方面。市场上有许多工具&#xff0c;具有各种功能和价格。在这篇由两部分组成的文章中&#xff0c;我们将重点介绍 Elementary 的…

计网简简单单复习一下

文章目录 基础体系结构(分层模型)为什么要分层?OSI 七层模型?每一层的作用?TCP/IP 四层模型是什么?每一层的作用是什么?五层体系结构以及对应的协议每一层常见协议有哪些?从输入 URL 到页面展示到底发生了什么?URI和URL的区别;forward和redirect的区别DNS作用是什么?D…

解析DNS查询报文,探索DNS工作原理

目录 1. 用 tcpdump工具监听抓包 2. 用 host 工具获取域名对应的IP地址 3. 分析DNS以太网查询数据帧 3.1 linux下查询DNS服务器IP地址 3.2 DNS以太网查询数据帧 &#xff08;1&#xff09;数据链路层 &#xff08;2&#xff09;网络层 &#xff08;3&#xff09;传输层…

828华为云征文 | Flexus X的力量,驱动Halo博客在云端飞驰

前言 华为云Flexus云服务器 X实例&#xff0c;以卓越性能与灵活配置&#xff0c;为Halo博客搭建起梦想的云端舞台。在这个828企业上云节节日里&#xff0c;华为云Flexus云服务器 X实例不仅提供了稳定高效的运行环境&#xff0c;更助力Halo博客实现内容创作的无限可能。无论是流…

maya的重命名物体和材质工具(带ai过程)

对材质同样也有效 被AI干失业的卖衣服的小姐姐&#xff0c;开的士的小哥哥都可以再就业的易上手教程&#xff0c; 先看效果&#xff01; 对物体命名也是&#xff0c;相当的美观 先提出需求我想在maya中批量重命名物体怎么办&#xff1f;AI给你弄个短代码 &#xff0c;放进AI进…

Android Studio Menu制作

文章目录 在Activity上新建onCreateOptionsMenu新建menu目录及资源文件新建Menu一级菜单在Activity上加载Menu 在Activity上新建onCreateOptionsMenu Overridepublic boolean onCreateOptionsMenu(Menu menu) {return super.onCreateOptionsMenu(menu);}新建menu目录及资源文件…

【前端】 flex布局详解

Flex布局开启&#xff0c;在编写之前&#xff0c;我们要先搞清楚一个问题&#xff0c;就是你要让谁开启flex布局&#xff1f;我们要开启flex布局的最终目的一定是为了让某几个元素进行规范化布局&#xff0c;那如果你单独写在某个元素身上&#xff0c;那它的兄弟元素也不知道自…

算法基础-约数

试除法求约数 public class Main {public static void main(String[] args){Scanner in new Scanner(System.in);int n in.nextInt();while(n -- > 0) {int x in.nextInt();List<Integer> list new ArrayList<>();for(int i 1; i < x / i; i ) {if(x % …

腾讯云2024年数字生态大会开发者嘉年华(数据库动手实验)必知必会的AI结合数据库案例

文章目录 腾讯云2024年数字生态大会开发者嘉年华&#xff08;数据库动手实验&#xff09;必知必会的AI结合数据库案例一、引言二、大会概览三、数据库发展现状与未来趋势讲解四、AI大模型的分析与应用讲解五、动手实验六、大会的社交七、个人感想与反思八、结论九、附录 腾讯云…