CyclicBarrier(应对并发问题的工具类)

CyclicBarrier

5.3.1 概述以及基本使用

CyclicBarrier的字面意思是可循环使用(Cyclic)的屏障(Barrier)。它要做的事情是,让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障

才会开门,所有被屏障拦截的线程才会继续运行。

例如:公司召集5名员工开会,等5名员工都到了,会议开始。我们创建5个员工线程,1个开会线程,几乎同时启动,使用CyclicBarrier保证5名员工线程全部执行后,再执行开会线程。

CyclicBarrier的相关方法

public CyclicBarrier(int parties, Runnable barrierAction)   // 用于在线程到达屏障时,优先执行barrierAction,方便处理更复杂的业务场景
public int await()											// 每个线程调用await方法告诉CyclicBarrier我已经到达了屏障,然后当前线程被阻塞

案例演示:模拟员工开会

实现步骤:

  1. 创建一个员工线程类(EmployeeThread),该线程类中需要定义一个CyclicBarrier类型的形式参数
  2. 创建一个开会线程类(MettingThread)
  3. 测试类
    1. 创建CyclicBarrier对象
    2. 创建5个EmployeeThread线程对象,把第一步创建的CyclicBarrier对象作为构造方法参数传递过来
    3. 启动5个员工线程

员工线程类

public class EmployeeThread extends Thread {// CyclicBarrier类型的成员变量private CyclicBarrier cyclicBarrier ;public EmployeeThread(CyclicBarrier cyclicBarrier) {        // 使用构造方法对CyclicBarrier进行初始化this.cyclicBarrier = cyclicBarrier ;}@Overridepublic void run() {try {// 模拟开会人员的随机到场Thread.sleep((int) (Math.random() * 1000));System.out.println(Thread.currentThread().getName() + " 到了! ");cyclicBarrier.await();} catch (Exception e) {e.printStackTrace();}}}

开会线程类

public class MettingThread extends Thread {@Overridepublic void run() {System.out.println("好了,人都到了,开始开会......");}}

测试类

public class CyclicBarrierDemo01 {public static void main(String[] args) {// 创建CyclicBarrier对象CyclicBarrier cyclicBarrier = new CyclicBarrier(5 , new MettingThread()) ;// 创建5个EmployeeThread线程对象,把第一步创建的CyclicBarrier对象作为构造方法参数传递过来EmployeeThread thread1 = new EmployeeThread(cyclicBarrier) ;EmployeeThread thread2 = new EmployeeThread(cyclicBarrier) ;EmployeeThread thread3 = new EmployeeThread(cyclicBarrier) ;EmployeeThread thread4 = new EmployeeThread(cyclicBarrier) ;EmployeeThread thread5 = new EmployeeThread(cyclicBarrier) ;// 启动5个员工线程thread1.start();thread2.start();thread3.start();thread4.start();thread5.start();}}

5.3.2 使用场景

使用场景:CyclicBarrier可以用于多线程计算数据,最后合并计算结果的场景。

比如:现在存在两个文件,这个两个文件中存储的是某一个员工两年的工资信息(一年一个文件),现需要对这两个文件中的数据进行汇总;使用两个线程读取2个文件中的数据,当两个文

件中的数据都读取完毕以后,进行数据的汇总操作。

分析:要想在两个线程读取数据完毕以后进行数据的汇总,那么我们就需要定义一个任务类(该类需要实现Runnable接口);两个线程读取完数据以后再进行数据的汇总,那么我们可以将

​ 两个线程读取到的数据先存储到一个集合中,而多线程环境下最常见的线程集合类就是ConcurrentHashMap,而这个集合需要被两个线程都可以进行使用,那么我们可以将这个集

​ 合作为我们任务类的成员变量,然后我们在这个任务类中去定义一个CyclicBarrier对象,然后在定义一个方法(count),当调用这个count方法的时候需要去开启两个线程对象,

​ 使用这两个线程对象读取数据,把读取到的数据存储到ConcurrentHashMap对象,当一个线程读取数据完毕以后,调用CyclicBarrier的awit方法(告诉CyclicBarrier我已经

​ 到达了屏障),然后在任务类的run方法对ConcurrentHashMap的数据进行汇总操作;

实现步骤:

  1. 定义一个任务类CyclicBarrierThreadUse(实现了Runnable接口)
  2. 定义成员变量:CyclicBarrier ,ConcurrentHashMap
private CyclicBarrier cyclicBarrier = new CyclicBarrier(2 , this) ;
private ConcurrentHashMap<Integer , String> concurrentHashMap = new ConcurrentHashMap<Integer , String>() ;
  1. 定义一个方法count方法,在count方法中开启两个线程对象(可以使用匿名内部类的方式实现)
  2. 在run方法中对ConcurrentHashMap中的数据进行汇总
  3. 编写测试类CyclicBarrierThreadUseDemo
  4. 创建CyclicBarrierThreadUse对象,调用count方法

任务类代代码:

public class CyclicBarrierThreadUse implements Runnable {// 当前我们两个线程到达了屏障点以后,我们需要立即对数据进行汇总, 因此我们需要使用第二个构造方法// 并且我们当前这个类就是一个任务类,因此我们可以直接传递参数thisprivate CyclicBarrier cyclicBarrier = new CyclicBarrier(2 , this) ;private ConcurrentHashMap<Integer , String> concurrentHashMap = new ConcurrentHashMap<Integer , String>() ;  // 存储两个线程所读取的数据public void count() {// 定义一个方法count方法,在count方法中开启两个线程对象(可以使用匿名内部类的方式实现)// 线程1new Thread(new Runnable() {@Overridepublic void run() {// 读取数据BufferedReader bufferedReader = null ;try {bufferedReader = new BufferedReader(new FileReader("D:\\salary\\2017-salary.txt")) ;String line = null ;while((line = bufferedReader.readLine()) != null) {concurrentHashMap.put(Integer.parseInt(line) , "") ;            // 小的问题,工资信息不能重复}} catch (Exception e) {e.printStackTrace();} finally {if(bufferedReader != null) {try {bufferedReader.close();} catch (IOException e) {e.printStackTrace();}}}// 模拟任务的执行时间try {TimeUnit.SECONDS.sleep(5) ;System.out.println(Thread.currentThread().getName() + "---------------------线程读取数据完毕....");cyclicBarrier.await() ;         //通知cyclicBarrier当前线程已经到达了屏障点} catch (Exception e) {e.printStackTrace();}}}).start();// 线程2new Thread(new Runnable() {@Overridepublic void run() {// 读取数据BufferedReader bufferedReader = null ;try {bufferedReader = new BufferedReader(new FileReader("D:\\salary\\2019-salary.txt")) ;String line = null ;while((line = bufferedReader.readLine()) != null) {concurrentHashMap.put(Integer.parseInt(line) , "") ;            // 小的问题,工资信息不能重复}} catch (Exception e) {e.printStackTrace();} finally {if(bufferedReader != null) {try {bufferedReader.close();} catch (IOException e) {e.printStackTrace();}}}// 模拟任务的执行时间try {TimeUnit.SECONDS.sleep(10) ;System.out.println(Thread.currentThread().getName() + "---------------------线程读取数据完毕....");cyclicBarrier.await() ;         //通知cyclicBarrier当前线程已经到达了屏障点} catch (Exception e) {e.printStackTrace();}}}).start();}@Overridepublic void run() {// 获取concurrentHashMap中的数据进行汇总Enumeration<Integer> enumeration = concurrentHashMap.keys();        // 获取concurrentHashMap中所有的键/*** 这个Enumeration的使用和我们之前所学习过的迭代器类似* boolean hasMoreElements(); 判断集合中是否存在下一个元素* E nextElement();           获取元素*/int result = 0 ;while(enumeration.hasMoreElements()) {Integer integer = enumeration.nextElement();result += integer ;}// 输出System.out.println(result);}}

测试类代码:

public class CyclicBarrierThreadUseDemo01 {public static void main(String[] args) {// 创建任务类的对象CyclicBarrierThreadUse cyclicBarrierThreadUse = new CyclicBarrierThreadUse();// 调用count方法进行数据汇总cyclicBarrierThreadUse.count();}}

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

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

相关文章

JNPF低代码开发平台:推进供应链数字化进程

随着全球贸易的日益频繁和市场竞争的加剧&#xff0c;供应链的数字化已经成为企业提高竞争力、降低成本、提高效率的关键因素。在这个过程中&#xff0c;低代码开发平台以其高效、灵活的特点&#xff0c;成为了推动供应链数字化进程的重要工具。本文将以JNPF低代码开发平台为例…

PgSQL-添加列、字段的注释

mysql是&#xff1a; 添加列&#xff1a;--alter table 表名 add column 列名 varchar(30);ALTER TABLE p_show ADD COLUMN points VARCHAR(100) COMMENT 所需积分;---------------------------------------------------------------------------------------------添加、修改…

与神对话-2

目录 三卷书&#xff0c;它们是&#xff1a; 第一卷将主要涉及个人问题&#xff0c;聚焦在个人生活中的各种挑战和机遇。第二卷将涉及更带全球性的问题&#xff0c;这个星球上的地域政治和超自然的生活。以及这个世界正在面临的挑战。第三卷将涉及最高秩序的宇宙真理&#xf…

Jmeter性能 之 “查看结果树” 界面功能介绍

前言 查看结果树 显示所有请求响应的树&#xff0c;通过它可以查看任何请求的响应。除了显示响应之外&#xff0c;还可以查看获取响应所花费的时间以及一些响应代码。需要通过"查看结果树"来查看服务器处理请求之后的返回结果&#xff0c;分析是否存在问题 注意&am…

Typora v1.8.6解锁版安装教程 (轻便简洁的Markdown编辑器)

前言 Typora是一款轻便简洁的Markdown编辑器&#xff0c;支持即时渲染技术&#xff0c;这也是与其他Markdown编辑器最显著的区别。即时渲染使得你写Markdown就想是写Word文档一样流畅自如&#xff0c;不像其他编辑器的有编辑栏和显示栏。 一、下载地址 下载链接&#xff1a;…

传染病报卡内容——丙型

--丙型 select a.morbiditdate 发病日期, diagnosedate 诊断日期, a.deathdate 死亡日期, a.casetypequality 病例分类,a.hcvrna "HCR_RNA定量" from zl_sdmb.t_报卡记录 t, c1_infectiousv1_6 a where t.id a.fileid and t.卡片种类 传…

架构设计 - 本地热点缓存

摘要&#xff1a; 缓存体系架构&#xff1a; 一级缓存&#xff1a;JVM本地缓存 二级缓存&#xff1a;Redis集中缓存 三级缓存&#xff1a;Nginx缓存&#xff08;Proxy Cache缓存&#xff1b;Lua缓存&#xff09; Java&#xff08;或任何编程语言&#xff09;中的本地热点缓…

游戏测试工程师面试,常问的问题有哪些?

一般会在面试中了解以下方面&#xff1a; 1.游戏热情&#xff0c;理解程度 玩过哪些游戏&#xff0c;这些游戏玩过多长时间&#xff0c;玩到什么样的水平&#xff0c;在游戏里花过多少钱 你觉得游戏里&#xff0c;xxx的设计如何&#xff0c;评价一下 2.编程、测试相关 学过哪…

使用注解配置定义和管理 Spring Bean

Spring 框架提供了多种方式来定义和管理 Bean&#xff0c;其中使用注解配置是现代 Spring 应用程序中最常用和推荐的方式。注解配置简化了 Bean 的定义和依赖注入过程&#xff0c;使代码更简洁、更易读。本文将详细介绍如何使用注解配置来定义和管理 Spring Bean。 一、Spring…

任务3.8.3 利用RDD统计每日新增用户

任务目标 统计给定用户访问历史数据中&#xff0c;每日的新增用户数量。 数据准备 原始数据格式&#xff1a;每行包含两个字段&#xff0c;日期和用户名&#xff0c;以逗号分隔。示例数据&#xff1a;2024-05-01,mike 2024-05-01,alice 2024-05-01,brown ...解决方案 使用倒…

【2024.6.21】今日科技时事:科技前沿大事件

人不走空 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌赋&#xff1a;斯是陋室&#xff0c;惟吾德馨 目录 &#x1f308;个人主页&#xff1a;人不走空 &#x1f496;系列专栏&#xff1a;算法专题 ⏰诗词歌…

Notepad++插件 Hex-Edit

Nptepad有个Hex文件查看器&#xff0c;苦于每次打开文件需要手动开插件显示Hex&#xff0c;配置一下插件便可实现打开即调用 关联多个二进制文件&#xff0c;一打开就使用插件的方法&#xff0c;原来是使用空格分割&#xff01;&#xff01;&#xff01;

Java图形用户界面设计AWT事件处理

AWT事件处理 前言一、GUI事件处理机制定义使用步骤Swing事件处理机制与AWT的区别 二、GUI中常见事件和事件监听器事件低级事件高级事件 事件监听器AWT事件类的继承关系 三、事件适配器三、示例代码示例示例一示例二 示例三 前言 推荐一个网站给想要了解或者学习人工智能知识的…

Hi3861 OpenHarmony嵌入式应用入门--LiteOS Thread

目录 Thread API 主要接口说明 测试代码编写 代码分析 hi3861使用的实时系统主要是基于Huawei LiteOS-M&#xff0c;这是华为针对物联网领域推出的轻量级物联网操作系统内核。LiteOS-M是Huawei LiteOS的一个分支&#xff0c;专为IoT领域构建&#xff0c;主要面向没有MMU&am…

sqlmap使用以及GUI安装

下载 GUI版地址: GitHub - honmashironeko/sqlmap-gui: 基于官版本 SQLMAP 进行人工汉化&#xff0c;并提供GUI界面及多个自动化脚本 GUI使用 可以点击.bat启动 如果点击.bat启动不了就在这里打开cmd,输入对应的.bat来启动 linux安装 地址:sqlmap: automatic SQL injection…

c++中串口的安全封装使用

固定缓冲区大小&#xff1a;在这种情况下&#xff0c;你将缓冲区大小固定为4096字节。如果你的数据量可能超过这个限制&#xff0c;可能需要反复调用读取操作以确保读取完整的数据。 局部变量初始化&#xff1a;在C中&#xff0c;局部变量如果不是内置类型&#xff08;如int、…

Java基础——String类详解,实用解释

String类(不是基本数据类型) - String的不可变性 在 Java 8 中&#xff0c; String 内部使用 char 数组存储数据。并且被声明为 final &#xff0c;因此它不可被继承。 public final class String implements java.io.Serializable, Comparable<String>, CharSequence…

记忆化搜索——AcWing 901. 滑雪

记忆化搜索 定义 记忆化搜索是一种结合了搜索和动态规划思想的方法。它通过将已经计算过的结果存储起来&#xff0c;在后续遇到相同情况时直接返回存储的结果&#xff0c;避免重复计算。 运用情况 当问题可以用递归方式求解&#xff0c;但存在大量重复计算时。一些复杂的组…

python从入门到精通3:变量

在Python编程中&#xff0c;变量是一个非常重要的概念。它们用于存储数据&#xff0c;并在程序执行过程中进行数据的读取、修改和传递。理解变量的概念、命名规则、数据类型以及作用域&#xff0c;对于编写高效、健壮的Python代码至关重要。下面&#xff0c;我们将对Python变量…

收藏||电商数据采集流程||电商数据采集API接口

商务数据分析的流程 第一步&#xff1a;明确分析目的。首先要明确分析目的&#xff0c;并把分析目的分解成若干个不同的分析要点&#xff0c;然后梳理分析思路&#xff0c;最后搭建分析框架。 第二步&#xff1a;数据采集。主流电商API接口数据采集&#xff0c;一般可以通过数…