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

news2024/9/25 7:15:14

文章目录

    • 同步工具类
    • 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.coloradmin.cn/o/2126263.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

泰勒斯威夫特是认真的:我已经做过研究我做出了选择,支持哈里斯 !呼吁粉丝赶紧投票!

泰勒说她将投票给哈里斯,因为"她为权利而战,我相信需要一个战士来捍卫他们。" 泰勒:这真的让我对人工智能产生了恐惧 当拥有3亿多粉丝的碧昂丝将主题曲授权给哈里斯的时候就已经暗示了她的倾向性 如果碧昂丝和斯威夫特6亿粉丝的哈里斯选票转化率为30%&#xff0c;…

全国各地身份证号开头6位数字及地区对照表

具体请前往&#xff1a;全国各地身份证号开头6位数字-省市县/区对照表

计算语言学(一)基础

概率论的几个概念 熵、互信息 神经网络基础 MLP CNN RNN Seq2Seq LSTM Transformer 语料库与知识库

L2线性回归模型

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 鸢尾花数据集的单变量与多变量预测 在这周学习如何使用 机器学习 模型对鸢尾花&#xff08;Iris&#xff09;数据集进行单变量与多变量预测。我们将使用鸢尾花…

北京中实新材料公司:安全筑基,共绘新材料产业新篇章

北京中实新材料有限责任公司(以下简称“北京中实”),作为中关村科技发展(控股)股份有限公司旗下的重要成员,近年来在安全生产、技术创新及企业合作等方面取得了显著进展。近期,公司围绕安全生产月及新材料研发中心成立等核心活动,展开了一系列富有成效的工作,进一步推动了企业的…

【Java算法】递归

&#x1f525;个人主页&#xff1a; 中草药 &#x1f525;专栏&#xff1a;【算法工作坊】算法实战揭秘 &#x1f347;一.递归 概念 递归是一种解决问题的方法&#xff0c;其中函数通过调用自身来求解问题。这种方法的关键在于识别问题是否可以被分解为若干个相似但规模更小…

深入Redis:复杂的集群

广义的集群&#xff0c;可能说只要是多台机器组成了分布式系统&#xff0c;就可以称之为集群。 狭义的集群&#xff0c;指的是Redis提供的集群模式&#xff0c;这个集群模式之下&#xff0c;主要是解决存储空间不足的问题&#xff0c;以及如何拓展存储空间。 之前的哨兵模式&…

C++中string的简单实现

string的简单实现中一些函数的实现可以复用一些其他的函数来实现&#xff1b;比较重要的是在实现是深浅拷贝问题 目录 string的结构 实现构造和析构 reserve扩容 容量 push_back和append insert和erase的实现 swap的实现&#xff08;不是成员函数但是string类的友元&…

【c++】类和对象详解

✅博客主页:爆打维c-CSDN博客​​​​​​ &#x1f43e; &#x1f539;分享c语言知识及代码 来都来了! 点个赞给博主个支持再走吧~&#xff01; 一.类的定义 &#xff08;1&#xff09;类定义格式 class为类定义的关键字&#xff0c;定义一个类格式如下: class 类名{//代码…

kubelet 探针

目录 1 k8s中kubelet 探针的介绍 1.1 探针是由 kubelet 对容器执行的定期诊断: 1.2 Kubelet 可以选择是否执行在容器上运行的三种探针执行和做出反应&#xff1a; 1.3 ReadinessProbe 与 LivenessProbe 的区别 1.4 StartupProbe 与 ReadinessProbe、LivenessProbe 的区别 2 实…

CCRC-DSA数据安全评估师:网络安全风险评估

1.网络安全风险评估概述 1.1概念 在当今信息化时代&#xff0c;网络安全成为了组织不可或缺的一部分。 风险评估作为一种科学方法&#xff0c;其目的是对网络系统的保密性、完整性、可控性和可用性这四个核心安全属性进行深入分析。 这一过程不仅包括识别网络系统中存在的脆…

Snipaste无法使用F1、F3等快捷键的保姆级解决方法

在Snipaste中按F1、F3等快捷键无效的可能原因&#xff1a; 1. 软件设置&#xff1a; 检查Snipaste的设置&#xff0c;确保F1被正确设置为截屏热键&#xff0c;并确认没有其他软件占用或冲突。 2. 热键冲突&#xff1a; 笔记本电脑的功能键&#xff08;F1-F12&#xff09;通常…

MySQL 数据库:原理、应用与发展

摘要&#xff1a;本文深入探讨了 MySQL 数据库相关内容。首先介绍了 MySQL 作为开源关系型数据库管理系统的显著特点&#xff0c;包括易用性、跨平台性、高性能、可扩展性、开源免费以及数据安全性等方面。接着详细阐述了其安装与配置过程&#xff0c;涵盖在不同操作系统上的安…

STM32使用 :串口的接收与发送

一、串口 在 STM32 中&#xff0c;串口&#xff08;UART&#xff0c;通用异步收发传输器&#xff09;是用于串行通信的外设。它在嵌入式系统中的作用非常广泛&#xff0c;主要包括几个方面 数据通信 串口用于微控制器与其他设备之间的数据传输。这些设备可以是其他微控制器、…

F12抓包08:查看网站Cookie

课程大纲 1、查看Cookie 1. 应用界面查看&#xff1a;按F12进入浏览器的开发者模式 - “应用”&#xff08;Application&#xff09; - Cookie&#xff0c;可查看Cookie并进行增、删、改、查操作。 2. 控制台命令行查看&#xff1a;按F12进入浏览器的开发者模式 - “控制台”&…

【无标题】nginx服务器代码信息、数据库连接信息、敏感文件的路径、服务器版本信息发起有针对性的攻击

Nginx敏感文件的路径、服务器版本信息 Nginx 403、404、500等错误时&#xff0c;返回详细错误信息。报错信息中可能会包含服务器代码信息、数据库连接信息、敏感文件的路径、服务器版本信息等&#xff0c;攻击者可以利用这些信息来寻找已知的漏洞&#xff0c;从而发起有针对性…

『功能项目』管理器基类【38】

我们打开上一篇37单例模式框架的项目&#xff0c; 本章要做的事情是编写管理器基类 首先创建脚本&#xff1a;ManagerBase.cs using UnityEngine; public abstract class ManagerBase : MonoBehaviour{public virtual void Init() { } } public class ManagerBase<T> : …

【Qt系列样式表】探索Qt Widget的艺术化设计与应用(Macos风格)(持续更新中...)

✨✨ Rqtz 个人主页 : 点击✨✨ &#x1f308;Qt系列专栏:点击 &#x1f388;PyQt系列专栏:点击&#x1f388; &#x1f388;Qt智能车上位机专栏: 点击&#x1f388; &#x1f388;Qt串口助手专栏:点击&#x1f388; &#x1f4ab;宗旨:共享IT之美,共创机器未来 目录 界面…

毕业论文word页眉页脚和页码的问题

多找B站视频查看视频操作方法。 问题1&#xff1a; 不同章节的页眉显示不同内容。 解决办法&#xff1a; “布局”里面插入分节符 &#xff08;非 分页符。&#xff09; 问题2&#xff1a; 页眉需要奇偶页内容不同 解决办法&#xff0c;编辑页眉部分&#xff0c;设置 奇偶页…

Qt (15)【Qt窗口 —— 字体对话框 QFontDialog | 输入对话框 QInputDialog】

阅读导航 引言一、字体对话框 QFontDialog1. 简介2. 基本用法3. 示例代码 二、输入对话框 QInputDialog1. 简介2. 基本用法&#xff08;1&#xff09;双精度浮点型输入数据对话框&#xff08;2&#xff09;整型输入数据对话框&#xff08;3&#xff09;选择条目型输入数据框 3.…