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…...
Linux 文件类型,目录与路径,文件与目录管理
文件类型 后面的字符表示文件类型标志 普通文件:-(纯文本文件,二进制文件,数据格式文件) 如文本文件、图片、程序文件等。 目录文件:d(directory) 用来存放其他文件或子目录。 设备…...
Docker 运行 Kafka 带 SASL 认证教程
Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明:server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...
定时器任务——若依源码分析
分析util包下面的工具类schedule utils: ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类,封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz,先构建任务的 JobD…...
Nginx server_name 配置说明
Nginx 是一个高性能的反向代理和负载均衡服务器,其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机(Virtual Host)。 1. 简介 Nginx 使用 server_name 指令来确定…...
vue3 定时器-定义全局方法 vue+ts
1.创建ts文件 路径:src/utils/timer.ts 完整代码: import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 创建定时器con…...
【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具
第2章 虚拟机性能监控,故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令:jps [options] [hostid] 功能:本地虚拟机进程显示进程ID(与ps相同),可同时显示主类&#x…...
使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台
🎯 使用 Streamlit 构建支持主流大模型与 Ollama 的轻量级统一平台 📌 项目背景 随着大语言模型(LLM)的广泛应用,开发者常面临多个挑战: 各大模型(OpenAI、Claude、Gemini、Ollama)接口风格不统一;缺乏一个统一平台进行模型调用与测试;本地模型 Ollama 的集成与前…...
html-<abbr> 缩写或首字母缩略词
定义与作用 <abbr> 标签用于表示缩写或首字母缩略词,它可以帮助用户更好地理解缩写的含义,尤其是对于那些不熟悉该缩写的用户。 title 属性的内容提供了缩写的详细说明。当用户将鼠标悬停在缩写上时,会显示一个提示框。 示例&#x…...
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中,新增了一个本地验证码接口 /code,使用函数式路由(RouterFunction)和 Hutool 的 Circle…...
力扣热题100 k个一组反转链表题解
题目: 代码: func reverseKGroup(head *ListNode, k int) *ListNode {cur : headfor i : 0; i < k; i {if cur nil {return head}cur cur.Next}newHead : reverse(head, cur)head.Next reverseKGroup(cur, k)return newHead }func reverse(start, end *ListNode) *ListN…...
