【JAVA】CyclicBarrier源码解析以及示例

文章目录

      • 前言
      • CyclicBarrier源码解析以及示例
        • 主要成员变量
        • 核心方法
      • 应用场景
        • 任务分解与合并
          • 应用示例
        • 并行计算
          • 应用示例
        • 游戏开发
          • 应用示例
          • 输出结果
        • 数据加载
          • 应用示例
        • 并发工具的协同
        • 应用示例
      • CyclicBarrier和CountDownLatch的区别
        • 循环性:
        • 计数器的变化:
        • 用途:
        • 构造函数参数:
      • 专栏集锦
      • 总结
      • 写在最后

579a429daf314744b995f37351b46548

前言

在多线程编程中,同步工具是确保线程之间协同工作的重要组成部分。

CyclicBarrier(循环屏障)是Java中的一个强大的同步工具,它允许一组线程在达到某个共同点之前互相等待。

在本文中,我们将深入探讨CyclicBarrier的源码实现以及提供一些示例,以帮助您更好地理解和应用这个有趣的同步工具。


CyclicBarrier源码解析以及示例

主要成员变量
public class CyclicBarrier {private final ReentrantLock lock = new ReentrantLock();private final Condition trip = lock.newCondition();private final int parties;private int count;private final Runnable barrierCommand;
}
  • lock: 用于控制并发访问的重入锁。
  • trip: 条件变量,用于在屏障点上等待。
  • parties: 表示需要等待的线程数。
  • count: 表示当前已经到达屏障点的线程数。
  • barrierCommand: 在所有线程到达屏障点之后执行的命令,可以为null。
核心方法

await方法

public int await() throws InterruptedException, BrokenBarrierException {try {lock.lock();if (Thread.interrupted())throw new InterruptedException();int index = --count;if (index == 0) { // 如果是最后一个到达的线程boolean ranAction = false;try {final Runnable command = barrierCommand;if (command != null)command.run();ranAction = true;return 0;} finally {if (!ranAction)breakBarrier(); // 执行失败,重置屏障状态}}while (index > 0) {try {trip.await();} catch (InterruptedException ie) {if (index == 1 && !broken)breakBarrier();throw ie;}}if (broken)throw new BrokenBarrierException();return index;} finally {lock.unlock();}
}

上述代码主要完成以下几个任务:

  1. 减小计数器,表示有一个线程到达了屏障点。
  2. 如果是最后一个到达的线程,执行屏障命令(如果有),然后唤醒所有等待的线程。
  3. 如果不是最后一个到达的线程,进入等待状态,直到被唤醒。
  4. 处理中断异常和屏障破坏异常。

应用场景

任务分解与合并

当一个大任务可以分解为多个子任务,每个子任务独立执行,但在某个点上需要等待所有子任务完成后再继续执行父任务。CyclicBarrier可以用来同步这些子任务的执行,确保它们在特定的屏障点上等待,然后一起继续执行。

应用示例

假设我们有一个大型的数据处理任务,需要将数据分解为若干子任务并行处理,然后在所有子任务完成后进行结果的合并。CyclicBarrier 可以用来同步子任务的执行,确保在所有子任务都完成后再进行合并操作。

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;public class TaskDecompositionAndMergeExample {private static final int NUM_SUBTASKS = 3;private static final CyclicBarrier barrier = new CyclicBarrier(NUM_SUBTASKS, () -> {System.out.println("All subtasks have been completed. Merging results...");});public static void main(String[] args) {for (int i = 0; i < NUM_SUBTASKS; i++) {final int subtaskId = i;new Thread(() -> {// Perform individual subtaskSystem.out.println("Subtask " + subtaskId + " is processing.");// Simulate some computation for the subtasktry {Thread.sleep((long) (Math.random() * 1000));} catch (InterruptedException e) {e.printStackTrace();}System.out.println("Subtask " + subtaskId + " has completed.");try {// Wait for all subtasks to completebarrier.await();} catch (InterruptedException | BrokenBarrierException e) {e.printStackTrace();}}).start();}}
}
并行计算

在并行计算中,当多个计算节点完成局部计算后,需要将它们的结果合并。CyclicBarrier可以用来等待所有计算节点完成局部计算,然后执行合并操作。

应用示例
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;public class ParallelComputingExample {private static final int NUM_THREADS = 4;private static final CyclicBarrier barrier = new CyclicBarrier(NUM_THREADS, () -> {System.out.println("All threads have completed the computation. Merging results...");});public static void main(String[] args) {for (int i = 0; i < NUM_THREADS; i++) {final int threadId = i;new Thread(() -> {// Perform individual computationSystem.out.println("Thread " + threadId + " is performing computation.");// Simulate some computation for the threadtry {Thread.sleep((long) (Math.random() * 1000));} catch (InterruptedException e) {e.printStackTrace();}System.out.println("Thread " + threadId + " has completed computation.");try {// Wait for all threads to complete computationbarrier.await();} catch (InterruptedException | BrokenBarrierException e) {e.printStackTrace();}}).start();}}
}
游戏开发

在多线程游戏开发中,可能存在多个线程分别负责不同的任务,比如渲染、物理模拟、AI计算等。

在每一帧结束时,这些线程需要同步,确保下一帧开始时所有任务都已完成。CyclicBarrier可以在每一帧结束时等待所有任务完成,然后统一开始下一帧的计算。

比如我们在打匹配游戏的时候,十个人必须全部加载到100%,才可以开局。否则只要有一个人没有加载到100%,那这个游戏就不能开始。先加载完成的玩家必须等待最后一个玩家加载成功才可以。

应用示例
public class CyclicBarrierDemo {private static CyclicBarrier cyclicBarrier;static class CyclicBarrierThread extends Thread{@Overridepublic void run() {System.out.println("玩家 " + Thread.currentThread().getName() + " 加载100%");//等待try {cyclicBarrier.await();} catch (Exception e) {e.printStackTrace();}}}public static void main(String[] args){cyclicBarrier = new CyclicBarrier(10, new Runnable() {public void run() {System.out.println("玩家都加载好了,开始游戏....");}});for(int i = 0 ; i < 10 ; i++){new CyclicBarrierThread().start();}}
}
输出结果
玩家 Thread-0 加载100%
玩家 Thread-2 加载100%
玩家 Thread-3 加载100%
玩家 Thread-6 加载100%
玩家 Thread-1 加载100%
玩家 Thread-4 加载100%
玩家 Thread-5 加载100%
玩家 Thread-8 加载100%
玩家 Thread-7 加载100%
玩家 Thread-9 加载100%
玩家都加载好了,开始游戏....
数据加载

在某些应用中,可能需要同时加载多个数据源,但要确保所有数据加载完成后再继续执行。CyclicBarrier可以用来等待所有数据加载完成,然后执行后续操作。

应用示例
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;public class DataLoaderExample {private static final int NUM_THREADS = 3;private static final CyclicBarrier barrier = new CyclicBarrier(NUM_THREADS, () -> {System.out.println("All data loading threads have completed. Initiating further processing...");});public static void main(String[] args) {for (int i = 0; i < NUM_THREADS; i++) {final int threadId = i;new Thread(() -> {// Simulate data loadingSystem.out.println("Thread " + threadId + " is loading data.");// Simulate data loading timetry {Thread.sleep((long) (Math.random() * 1000));} catch (InterruptedException e) {e.printStackTrace();}System.out.println("Thread " + threadId + " has completed data loading.");try {// Wait for all data loading threads to completebarrier.await();} catch (InterruptedException | BrokenBarrierException e) {e.printStackTrace();}// Perform further processing after data loading is completeSystem.out.println("Thread " + threadId + " is performing further processing.");}).start();}}
}
并发工具的协同

CyclicBarrier可以与其他并发工具一起使用,例如 ExecutorServiceCountDownLatch,以实现更复杂的多线程控制逻辑。

应用示例
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;public class CyclicBarrierExample {private static final int NUM_THREADS = 3;private static final CyclicBarrier barrier = new CyclicBarrier(NUM_THREADS, () -> {System.out.println("All threads have reached the barrier. Let's continue!");});public static void main(String[] args) {for (int i = 0; i < NUM_THREADS; i++) {new Thread(() -> {try {// Perform individual tasksSystem.out.println(Thread.currentThread().getName() + " is performing individual tasks.");// Wait for all threads to reach the barrierbarrier.await();// Continue with collective tasks after reaching the barrierSystem.out.println(Thread.currentThread().getName() + " is performing collective tasks.");} catch (InterruptedException | BrokenBarrierException e) {e.printStackTrace();}}).start();}}
}

CyclicBarrier和CountDownLatch的区别

循环性:
  • CyclicBarrier 具有循环的特性,可以被重复使用。一旦所有线程都到达屏障点,它会自动重置并再次等待下一轮。这使得 CyclicBarrier 更适合用于一组线程多次协同工作的场景。
  • CountDownLatch 是一次性的,一旦计数到达零,就无法重新设置。如果需要多次等待,就需要创建新的 CountDownLatch 实例。
计数器的变化:
  • CyclicBarrier 中,计数器的递减是由到达屏障点的线程执行的,而且在所有线程都到达之前,任何线程都不会继续执行。
  • CountDownLatch 中,计数器的递减是由任意线程执行的,而且线程在递减计数器后可以继续执行,不必等待其他线程。
用途:
  • CyclicBarrier 通常用于一组线程并行执行任务,然后在某个点上等待彼此,然后再一起继续执行下一轮任务。例如,任务分解与合并、并行计算等场景。
  • CountDownLatch 用于等待一组线程完成某个任务后再执行其他任务。例如,主线程等待所有工作线程完成工作后再继续执行。
构造函数参数:
  • CyclicBarrier 的构造函数需要指定参与同步的线程数,以及在屏障点上执行的可选操作(Runnable)。
  • CountDownLatch 的构造函数需要指定计数的初始值。

专栏集锦

大佬们可以收藏以备不时之需:

Spring Boot 专栏:http://t.csdnimg.cn/peKde

ChatGPT 专栏:http://t.csdnimg.cn/cU0na

Java 专栏:http://t.csdnimg.cn/YUz5e

Go 专栏:http://t.csdnimg.cn/Jfryo

Netty 专栏:http://t.csdnimg.cn/0Mp1H

Redis 专栏:http://t.csdnimg.cn/JuTue

Mysql 专栏:http://t.csdnimg.cn/p1zU9

架构之路 专栏:http://t.csdnimg.cn/bXAPS


总结

通过本文,我们深入了解了CyclicBarrier的源码实现,并通过一个简单的示例演示了它的用法。

CyclicBarrier是一个强大的同步工具,可以帮助我们实现复杂的多线程协同任务。

在多线程编程中,理解和熟练使用这样的同步工具是至关重要的,能够确保线程之间的协同工作更加高效和可靠。


写在最后

感谢您的支持和鼓励! 😊🙏

如果大家对相关文章感兴趣,可以关注公众号"架构殿堂",会持续更新AIGC,java基础面试题, netty, spring boot, spring cloud等系列文章,一系列干货随时送达!

csdn-end

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

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

相关文章

[c]用指针进行四个数排序

#include<stdio.h> void swap(int*p1,int*p2)//定义函数&#xff0c;实现两个数值交换 {int temp;temp*p1;*p1*p2;*p2temp; } void psort( int *pa, int *pb,int *pc,int *pd) {int i1;for(i1;i<3;i)//对四个数排序&#xff0c;至少3次循环&#xff0c;交换过后是升序…

DDPM推导笔记

各位佬看文章之前&#xff0c;可以先去看看这个视频&#xff0c;并给这位up主点赞投币&#xff0c;这位佬讲解的太好了&#xff1a;大白话AI 1.前置知识的学习 1.1 正态分布特性 ​ &#xff08;1&#xff09;正态分布的概率密度函数 f ( x ) 1 2 π σ e − ( x − μ ) …

Android13音频录制适配

Android13音频录制适配 前言&#xff1a; 之前写过一篇音频录制的文章&#xff0c;当时是在Android10以下的手机可以成功录制和播放&#xff0c;但是Android10及以上手机提示创建文件失败&#xff0c;最近做过Android13的适配&#xff0c;索性一起把之前的录音也适配了&#…

Python 时间日期处理库函数

标准库 datetime >>> import datetime >>> date datetime.date(2023, 12, 20) >>> print(date) 2023-12-20 >>> date datetime.datetime(2023, 12, 20) >>> print(date) 2023-12-20 00:00:00 >>> print(date.strfti…

gem5 RubyPort: mem_request_port作用与连接 simple-MI_example.py

简介 回答这个问题&#xff1a;RubyPort的口下&#xff0c;一共定义了六个口&#xff0c;分别是mem_request_port&#xff0c;mem_response_port&#xff0c;pio_request_port&#xff0c;pio_response_port&#xff0c;in_ports, interrupt_out_ports&#xff0c;他们分别有什…

【异常】jdk21升级,asm报错Unsupported class file major version 65 springboot2 升级JDK21

【异常】jdk21升级&#xff0c;asm报错Unsupported class file major version 65 错误信息 Caused by: org.springframework.core.NestedIOException: ASM ClassReader failed to parse class file - probably due to a new Java class file version that isnt supported yet…

Java对接腾讯多人音视频房间示例

最近在对接腾讯的多人音视频房间&#xff0c;做一个类似于腾讯会议的工具&#xff0c;至于为什么不直接用腾讯会议&#xff0c;这个我也不知道&#xff0c;当然我也不敢问 首先是腾讯官方的文档地址&#xff1a;https://cloud.tencent.com/document/product/1690 我是后端所以…

CSS自适应分辨率 amfe-flexible 和 postcss-pxtorem:大屏高宽自适应问题

前言 继上篇《CSS自适应分辨率 amfe-flexible 和 postcss-pxtorem》。 发现一个有趣的问题&#xff0c;文件 rem.js 中按照宽度设置自适应&#xff0c;适用于大多数页面&#xff0c;但当遇到大屏就不那么合适了。 问题 使用宽度&#xff0c;注意代码第2 和 4 行&#xff1a;…

JAVA面试题分享一百九十九:RabbitMQ 发布确认高级

目录 一、前言 二、发布确认SpringBoot版本 介绍 实战 添加配置类 消息生产者 消息消费者 消息生产者发布消息后的回调接口 三、回退消息 介绍 四、实战 修改配置文件 修改回调接口 五、备份交换机 介绍 实战 修改高级确认发布 配置类 报警消费者 一、前言 …

基于单片机智能自动浇花系统设计

**单片机设计介绍&#xff0c;基于单片机智能自动浇花系统设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机的智能自动浇花系统是一种可以自动感知周围环境&#xff0c;并执行相应动作的系统。通过使用传感器检测土…

【Netty】NIO与Netty核心概念

目录 NIO编程NIO介绍NIO和BIO的比较缓冲区(Buffer)基本介绍常用API缓冲区对象创建添加数据读取数据 通道(Channel)基本介绍Channel常用类ServerSocketChannelSocketChannel Selector (选择器)基本介绍常用API介绍示例代码 NIO 三大核心原理 Netty核心概念Netty 介绍原生 NIO 存…

【QT表格-6】QTableWidget的currentCellChanged实现中途撤销

背景&#xff1a; 【QT表格-1】QStandardItem的堆内存释放需要单独delete&#xff0c;还是随QStandardItemModel的remove或clear自动销毁&#xff1f;-CSDN博客 【QT表格-2】QTableWidget单元格结束编辑操作endEditting_qtablewidget 单元格编辑事件-CSDN博客 【QT表格-3】Q…

【Chrome】ERR_SSL_PROTOCOL_ERROR问题

文章目录 前言一、下载二、使用步骤总结 前言 Edge升级最新版后&#xff0c;有的https访问不了&#xff0c;报如下错误 发现新版Chrome以及Chromium内核访问nginx ssl时报错&#xff0c;顺着这个思路接着查看到大佬的结论&#xff1a;服务器nginx使用的openssl版本过低&#…

C++入门【12-C++ 数组】

C 数组 C 支持数组数据结构&#xff0c;它可以存储一个固定大小的相同类型元素的顺序集合。数组是用来存储一系列数据&#xff0c;但它往往被认为是一系列相同类型的变量。 数组的声明并不是声明一个个单独的变量&#xff0c;比如 number0、number1、...、number99&#xff0…

控制理论simulink+matlab

控制理论下的simulink和matlab使用 根轨迹LQR控制器简单使用状态观测器设计 根轨迹 z [-1]; %开环传递函数的零点 p [0 -2 -3 -4]; %开环传递函数的系统极点 k 1; %开环传递函数的系数&#xff0c;反映在比例上 g zpk(z,p,k); %生成开环传递函数%生成的传递函数如…

社交网络分析(汇总)

这里写自定义目录标题 写在最前面社交网络分析系列文章汇总目录 提纲问题一、社交网络相关定义和概念提纲问题1. 社交网络、社交网络分析&#xff1b;2. 六度分隔理论、贝肯数、顿巴数&#xff1b;3. 网络中的数学方法&#xff1a;马尔科夫过程和马尔科夫链、平均场理论、自组织…

使用JDBC对数据库进行简单操作

用Connection获得了数据库连接对象后&#xff0c;可以用Statement类型进行数据库操作。 在Statement对象中&#xff0c;有三种&#xff0c;分别是Statement&#xff0c;PrepareStatement&#xff0c;CallableStatement。 这三个的区别在于&#xff1a; Statement 用于执行不…

KubePi JWT 默认密钥权限绕过漏洞复现(CVE-2023-22463)

0x01 产品简介 KubePi 是一款简单易用的开源 Kubernetes 可视化管理面板。 0x02 漏洞概述 KubePi 存在权限绕过漏洞,攻击者可通过默认 JWT 密钥获取管理员权限控制整个平台,使用管理员权限操作核心的功能。 0x03 影响范围 KubePi <= 1.6.2 0x04 复现环境 FOFA: ti…

【Jenkins】远程API接口:Java 包装接口使用示例

jenkins-rest 库是一个面向对象的 Java 项目&#xff0c;它通过编程方式提供对 Jenkins REST API 的访问&#xff0c;以访问 Jenkins 提供的一些远程 API。它使用 jclouds 工具包构建&#xff0c;可以轻松扩展以支持更多 REST 端点。其功能集不断发展&#xff0c;用户可以通过拉…

怎么压缩过大的GIF图片?几个步骤轻松搞定!

GIF图片由于其图片格式&#xff0c;本身就会很大&#xff0c;但是微信QQ还有一些其他的社交平台对上传的表情包是有限制的&#xff0c;这个时候就需要借助一些图片处理工具对GIF进行压缩。 下面就向大家介绍三种好用的方法并展示具体的操作步骤。 一、使用嗨格式压缩大师进行压…