CountDownLatch 和 CyclicBarrier的区别与详解
文章目录
- 一.CountDownLatch 和 CyclicBarrier的区别
- 二.详解
- 总结
- 用法
- CountDownLatch 用法
- CyclicBarrier 用法
一.CountDownLatch 和 CyclicBarrier的区别
- CountDownLatch和CyclicBarrier都是线程同步的工具类,都是基于
AQS
实现的; - CountDownLatch 的计数器是大于或等于线程数的,而CyclicBarrier是一定等于线程数;
- CountDownLatch 放行由其他线程控制而CyclicBarrier是由本身来控制的,CountDownLatch允许一个或多个线程一直等待,直到这些线程完成它们的操作,而CyclicBarrier不一样,它往往是当线程到达某状态后,暂停下来等待其他线程,等到所有线程均到达以后,才继续执行,二者的等待主体是不一样的;
- CountDownLatch调用await()通常是
主线程/调用线程
,而CyclicBarrier调用await()是在任务线程
调用的; - CountDownLatch 操作的是事件,阻塞足够多的次数即可,不管几个线程;而 CyclicBarrier 侧重点是线程,强调多个线程间互相等待,同时结束;
- CountDownLatch 是不可以重置的,所以
无法重用
;而 CyclicBarrier 则没有这个限制,可以重用
;
二.详解
CountDownLatch
是通过计数器
实现,每次完成一个任务后,计数器减一当为0时,CountDownLatch.await()方法的线程就可以恢复执行任务。
CountDownLatch
是基于AQS实现的,它的实现机制很简单,当我们在构建CountDownLatch对象时,传入的值其实就会赋值给 AQS 的关键变量state,执行countDown方法时,其实就是利用CAS 将state 减一,执行await方法时,其实就是判断state是否为0,不为0则加入到队列中,将该线程阻塞掉(除了头结点),因为头节点会一直自旋等待state为0,当state为0时,头节点把剩余的在队列中阻塞的节点也一并唤醒。
CyclicBarrier
是直接借助ReentrantLock加上Condition 等待唤醒的功能 进而实现的,在构建CyclicBarrier时,传入的值会赋值给CyclicBarrier内部维护count变量,也会赋值给parties变量(这是可以复用的关键),每次调用await时,会将count -1 ,操作count值是直接使用ReentrantLock来保证线程安全性,如果count不为0,则添加则condition队列中,如果count等于0时,则把节点从condition队列添加至AQS的队列中进行全部唤醒,并且将parties的值重新赋值为count的值(实现复用)
总结
CountDownlatch
基于AQS实现,会将构造CountDownLatch的入参传递至state,countDown()就是在利用CAS将state减-1,await()实际就是让头节点一直在等待state为0时,释放所有等待的线程
CyclicBarrier
则利用ReentrantLock和Condition,自身维护了count和parties变量。每次调用await将count-1,并将线程加入到condition队列上。等到count为0时,则将condition队列的节点移交至AQS队列,并全部释放。
用法
CountDownLatch 用法
从代码层面,CountDownLatch 的用法是:
// 设置10个计数
CountDownLatch countDownLatch = new CountDownLatch(10);
// 每次调用即可减1
countDownLatch.countDown();
// 其他线程一直等待减到0后,才继续执行
countDownLatch.await()
举个栗子:
假设有一个业务场景,我们要求把所有的图片上传到文件服务器,然后将图片的地址URL保存到数据库;
其中上传素材,我们可以使用多线程去上传,都上传完之后,再入库。
publicbooleandealVedoi(List<Vedio>vedioList){//每个线程处理的最大任务数intmaxNum=10;intthreadNums=0;Map<String,String>map=newConcurrentHashMap<String,String>((int)(vedioList.size()/0.75));if(vedioList.size()<maxNum){threadNums=1;}else{//获取当前系统可用的处理器核心数量threadNums=Runtime.getRuntime().availableProcessors()>vedioList.size()/maxNum?vedioList.size()/maxNum:Runtime.getRuntime().availableProcessors();}try{//创建固定线程数处理这批任务ExecutorServiceexecutor=Executors.newFixedThreadPool(threadNums);CountDownLatchcountDownLatch=newCountDownLatch(vedioList.size());Iterator<Vedio>iterator=vedioList.iterator();while(iterator.hasNext()){executor.submit(()->{Vediovedio=iterator.next();Stringurl=store(vedio);map.put(vedio.getName());countDownLatch.countDown();});}countDownLatch.await();//所有素材上传成功后,入库saveDataBase(map);}catch(InterruptedExceptione){e.printStackTrace();}
}
newFixedThreadPool 方法用于创建一个固定大小的线程池,其中参数指定线程池的大小(即线程数量)。
适合的线程池大小取决于你的具体需求和应用场景。以下几点是需要考虑的因素:
- 任务的性质: 如果你的任务是 CPU 密集型的(需要大量的计算和处理),那么线程池的大小通常与处理器的核心数相近或略多一些可能是合适的。这样可以充分利用 CPU 资源。如果任务是 I/O 密集型的(例如涉及网络请求或文件操作),则可能需要更多的线程,以充分利用等待 I/O 的时间。
- 可用的系统资源: 考虑可用的系统资源,包括 CPU 核心数、内存和其他正在运行的应用程序。如果系统资源有限,将线程池大小保持在合理的范围内,以避免过度消耗资源。
- 任务的数量和规模: 考虑任务的数量和规模。如果你预计会有大量的任务需要处理,并且这些任务是短暂的,那么增加线程池的大小可以提高并发处理能力。但是,如果任务的数量较少或任务的执行时间较长,可能不需要太多的线程。
需要注意的是,如果线程池的大小设置过大,可能会导致资源竞争、上下文切换开销增加,甚至对系统性能产生负面影响。因此,需要根据实际情况进行调整和测试,找到适合你应用程序的线程池大小。
综合考虑以上因素,你可以根据你的应用需求和性能测试来选择一个合适的线程池大小。通常情况下,线程池大小在 2 到 10 之间是一个常见的范围。根据实际情况进行调整和优化是最佳的做法。
CyclicBarrier 用法
从代码使用角度来说:
// 初始化值为5的栅栏
CyclicBarrier cyclicBarrier = new CyclicBarrier(5);
// 每个线程调用 await()
cyclicBarrier.await();
// 等到有 5 个线程都执行了 await() 之后,继续执行。
// 并且 栅栏的 计数器会自动重置为 5 ,可以接着用
然后我们模拟一个场景
在游戏中,选好英雄之后,会等待所有 5 个玩家进度条都到 100% 才开始游戏,我们可以使用 CyclicBarrier 来模拟这个场景
publicclassCyclicBarrierTest{privatefinalstaticExecutorServiceEXECUTOR_SERVICE=Executors.newFixedThreadPool(5);privatefinalstaticCyclicBarrierBARRIER=newCyclicBarrier(10);publicstaticvoidmain(String[]args){for(inti=0;i<5;i++){finalStringname="玩家"+i;EXECUTOR_SERVICE.execute(newRunnable(){@Overridepublicvoidrun(){try{Thread.sleep(2000);System.out.println(name+"已准备,等待其他玩家准备...");BARRIER.await();Thread.sleep(1000);System.out.println(name+"已加入游戏");}catch(InterruptedExceptione){System.out.println(name+"离开游戏");}catch(BrokenBarrierExceptione){System.out.println(name+"离开游戏");}}});}EXECUTOR_SERVICE.shutdown();}
}
相关文章:
CountDownLatch 和 CyclicBarrier的区别与详解
文章目录 一.CountDownLatch 和 CyclicBarrier的区别二.详解总结用法CountDownLatch 用法CyclicBarrier 用法 一.CountDownLatch 和 CyclicBarrier的区别 CountDownLatch和CyclicBarrier都是线程同步的工具类,都是基于AQS实现的;CountDownLatch 的计数器…...
Vue子组件向父组件传值(this.$emit()方法)
子组件使用this.$emit()向父组件传值 首先必须在父组件中引用子组件,然后实现传值 第一步 在父组件中引入子组件 使用import引入组件 import indexImportOrder from ./components/indexImportOrder 声明 //定义组件components:{indexImportOrder,}, 使用 &l…...

【C++】C/C++内存管理-new、delete
文章目录 一、C/C内存分布二、C/C中动态内存管理方式2.1 C语言中动态内存管理方式2.2 C内存管理方式 三、operator new和operator delete函数3.1 operator new和operator delete函数3.2 operator new与operator delete的类专属重载(了解) 四、new和delet…...

高手进阶之路---pyqt自定义信号
高手进阶之路—pyqt自定义信号 1.思考问题为什么要自定义信号,qt5本身已有信号槽函数 # pushButton 被clicked的时候connect 函数print self.pushButton.clicked.connect(self.print)def print(self):print("我被点击了")或者使用 # 需要引入 pyqtSlo…...

研磨设计模式day09原型模式
目录 场景 代码实现 有何问题 解决方案 代码改造 模式讲解 原型与new 原型实例与克隆出来的实例 浅度克隆和深度克隆 原型模式的优缺点 思考 何时选用? 相关模式 场景 代码实现 定义订单接口 package com.zsp.bike.day08原型模式;/*** 订单的接口*…...
(二)Redis——List
因为是 List,所以所有相关的命令都以 L 开头。 LPUSH / RPUSH LRANGE list 0 -1 -1 表示末尾 127.0.0.1:6379> LPUSH list a 1 127.0.0.1:6379> LRANGE list 0 -1 a 127.0.0.1:6379> LPUSH list b 2 127.0.0.1:6379> LRANGE list 0 -1 b a 127.0.0.…...

【Go Web 篇】Go 语言进行 Web 开发:构建高性能网络应用
随着互联网的快速发展,Web 开发已经成为了软件开发领域中不可或缺的一部分。随之而来的是对于更高性能、更高效的网络应用的需求。在这个领域,Go 语言因其并发性能、简洁的语法以及丰富的标准库而备受关注。本篇博客将深入探讨如何使用 Go 语言进行 Web …...

开悟Optimization guide for intermediate tracks
目录 认识模型 参考方案(按模块拆解) 认识模型 模型控制1名英雄进行镜像1 v 1对战 Actor集群资源为64核CPU 问题特点:单一公平对抗场景(同英雄镜像对赛),单位时间样本产能低,累计训练资源相…...

wx.request配置服务器域名,只能包含英文大小写字母、数字,解决办法
前言.小程序服务器域名配置常见错误及解决方法 1.配置入口: 小程序后台->-开发->开发设置->服务器域名 2.常见错误及原因分析: 3.实战中出现的错误 4.解决办法:应把域名后边的路径去掉,只写域名即可...
【有效的括号】
题目 1、左括号入栈 2、右括号出栈顶括号进行匹配 栈 typedef char STDataType; //元素为char类型 typedef struct Stack {STDataType* a;//动态的开辟空间int top;int capacity; }ST;void StackInit(ST* ps)//初始化 {assert(ps);ps->a (STDataType*)malloc(sizeof(STD…...

积跬步至千里 || 数学基础、算法与编程
数学基础、算法与编程 1. BAP 技能 BAP 技能是指基础(Basic)、算法(Algorithm)和编程(Programm)三种基本技能的深度融合。理工科以数学、算法与编程为根基,这三个相辅相成又各有区别。 (1)数学以线性代数为主要研究工具和部分微积分技术为手…...

Java单元测试 JUnit 5 快速上手
一、背景 什么是 JUnit 5?首先就得聊下 Java 单元测试框架 JUnit,它与另一个框架 TestNG 占据了 Java领域里单元测试框架的主要市场,其中 JUnit 有着较长的发展历史和不断演进的丰富功能,备受大多数 Java 开发者的青睐。 而说到…...

【Linux网络】TCP UDP socket HTTP webSocket之间的区别
目录 一、OSI & TCP/IP模型 二、几者之间的关系 三、HTTP 四、Socket 五、WebSocket 5.1、WebSocket 优点 一、OSI & TCP/IP模型 首先我们要了解OSI七层模型,和预支对应的TCP/IP 四层的模型。 用下面的图可以看出,TCP UDP 工作在传输层&…...

【面向大一新生IT技术社群招新啦,不来瞅瞅?】
个人名片: 🐼作者简介:一名大三在校生 🐻❄️个人主页:落798. 🐼个人WeChat:落798. 🕊️系列专栏:【零基础学java】 ----- 【重识c语言】 ---- 【计算机网络】—【Spri…...

分析系统 - 使用Python爬虫
在竞争激烈的市场环境中,了解和分析竞争对手的销售策略和市场表现对于企业的成功至关重要。本文将介绍如何利用Python爬虫建立低成本的销售竞争对手分析系统,探索其方法、工具和好处,并同时解决可能出现的问题。 销售竞争对手分析的目标是获取…...

strstr函数
目录 函数介绍: 函数分析: 使用案例: 函数介绍: 返回指向 str1 中第一次出现的 str2 的指针,如果 str2 不是 str1 的一部分,则返回一个空指针。 匹配过程不包括终止空字符,但它到此为止。 …...

[C++] string类常用接口的模拟实现
文章目录 1、前言2、遍历2.1 operator[ ]下标方式2.2 迭代器2.3 范围for2.4 c_str 3、容量相关3.1 size(大小)3.2 capacity(容量)3.3 empty(判空)3.4 clear(清理)3.5 reserve3.6 res…...
每日一学——防火墙
防火墙是网络安全的重要组成部分,可以帮助保护网络免受恶意攻击和未经授权的访问。以下是防火墙的基本配置步骤: 定义安全策略:防火墙通过安全策略来决定允许或拒绝网络流量。你需要定义适当的安全策略来保护你的网络。安全策略通常包括源IP地…...

常用数据库备份方法,sql数据库备份方法
在信息时代,数据成为了公司的主要资产。然而,数据的安全性和完整性也成为企业管理的重要组成部分。因此,数据库备份至关重要。本文将详细介绍几种常见的数据库备份方法。 全备份 全备份是指数据库中所有数据的备份,包括数据文件、…...

常见前端面试之VUE面试题汇总八
22. Vue 子组件和父组件执行顺序 加载渲染过程: 1.父组件 beforeCreate 2.父组件 created 3.父组件 beforeMount 4.子组件 beforeCreate 5.子组件 created 6.子组件 beforeMount 7.子组件 mounted 8.父组件 mounted 更新过程: 1. 父组件 befor…...

装饰模式(Decorator Pattern)重构java邮件发奖系统实战
前言 现在我们有个如下的需求,设计一个邮件发奖的小系统, 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其…...

2025年能源电力系统与流体力学国际会议 (EPSFD 2025)
2025年能源电力系统与流体力学国际会议(EPSFD 2025)将于本年度在美丽的杭州盛大召开。作为全球能源、电力系统以及流体力学领域的顶级盛会,EPSFD 2025旨在为来自世界各地的科学家、工程师和研究人员提供一个展示最新研究成果、分享实践经验及…...

练习(含atoi的模拟实现,自定义类型等练习)
一、结构体大小的计算及位段 (结构体大小计算及位段 详解请看:自定义类型:结构体进阶-CSDN博客) 1.在32位系统环境,编译选项为4字节对齐,那么sizeof(A)和sizeof(B)是多少? #pragma pack(4)st…...

Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)
概述 在 Swift 开发语言中,各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过,在涉及到多个子类派生于基类进行多态模拟的场景下,…...
Nginx server_name 配置说明
Nginx 是一个高性能的反向代理和负载均衡服务器,其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机(Virtual Host)。 1. 简介 Nginx 使用 server_name 指令来确定…...

C++ 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...
现有的 Redis 分布式锁库(如 Redisson)提供了哪些便利?
现有的 Redis 分布式锁库(如 Redisson)相比于开发者自己基于 Redis 命令(如 SETNX, EXPIRE, DEL)手动实现分布式锁,提供了巨大的便利性和健壮性。主要体现在以下几个方面: 原子性保证 (Atomicity)ÿ…...

莫兰迪高级灰总结计划简约商务通用PPT模版
莫兰迪高级灰总结计划简约商务通用PPT模版,莫兰迪调色板清新简约工作汇报PPT模版,莫兰迪时尚风极简设计PPT模版,大学生毕业论文答辩PPT模版,莫兰迪配色总结计划简约商务通用PPT模版,莫兰迪商务汇报PPT模版,…...

C# 表达式和运算符(求值顺序)
求值顺序 表达式可以由许多嵌套的子表达式构成。子表达式的求值顺序可以使表达式的最终值发生 变化。 例如,已知表达式3*52,依照子表达式的求值顺序,有两种可能的结果,如图9-3所示。 如果乘法先执行,结果是17。如果5…...