当前位置: 首页 > news >正文

多线程控制并发数目工具类Semaphore

文章目录

    • 前言
    • Semaphore原理
    • Semaphore源码解析
      • 内部继承AQS保证同步
      • acquire获取许可
      • release释放许可
    • 实战演示
    • 总结

前言

在多线程编码过程中,我们会用到多线程来提升运行效率。比如我们的Executors创建线程池,程序尽可能的压榨CPU资源来提升我们程序吞吐量。但是过度的使用线程,也会将我们CPU资源榨干,从而让我们系统不能正常的提供服务。故今天我们引入JUC并发包下面的semaphore并发类,该类可以同时允许定量线程执行从而达到控制并发的目的。

Semaphore原理

Semaphore并发类提供了两个核心方法:acquire()方法和release()方法。acquire()方法表示获取一个许可,如果没有则等待,release()方法则是释放对应的许可。Semaphore维护了当前访问的个数,通过提供同步机制来控制同时访问的个数。

Semaphore源码解析

内部继承AQS保证同步

Semaphore 与AQS关系图:
在这里插入图片描述

进入java.util.concurrent 包下 Semaphore 并发类查看源码:

//继承AQS同步阻塞队列来实现同步功能
abstract static class Sync extends AbstractQueuedSynchronizer {private static final long serialVersionUID = 1192457210091910933L;Sync(int permits) {setState(permits);}final int getPermits() {return getState();}final int nonfairTryAcquireShared(int acquires) {for (;;) {int available = getState();int remaining = available - acquires;if (remaining < 0 ||compareAndSetState(available, remaining))return remaining;}}

如上所示,首先Semaphore并发内部类继承AbstractQueuedSynchronizer 同步阻塞类,所以可以得出Semaphore是通过AQS机制来保证同步。AQS不明白的同学可以看我之前的博文,大概就是内部一个state状态,获取到资源 state 就加一,释放资源 state 就减一,当 state == 0 的时候表示阻塞队列中的其他线程可以获取该资源。

继续查看源码:

/*** Creates a {@code Semaphore} with the given number of* permits and nonfair fairness setting.** @param permits the initial number of permits available.*        This value may be negative, in which case releases*        must occur before any acquires will be granted.*/
public Semaphore(int permits) {sync = new NonfairSync(permits);
}/*** Creates a {@code Semaphore} with the given number of* permits and the given fairness setting.** @param permits the initial number of permits available.*        This value may be negative, in which case releases*        must occur before any acquires will be granted.* @param fair {@code true} if this semaphore will guarantee*        first-in first-out granting of permits under contention,*        else {@code false}*/
public Semaphore(int permits, boolean fair) {sync = fair ? new FairSync(permits) : new NonfairSync(permits);
}

如源码所示,Semaphore构造方法默认提供非公平锁同步构造方法,也提供了一个用户自定义是否公平锁的构造方法。是否公平锁同步直接影响阻塞队列中的哪个线程可以获取资源,公平锁是按照阻塞顺序获取资源,非公平锁是多个线程争抢资源。当然构造方法必须传入并发许可的总数,这个总数直接影响后续我们可以同时获取多少个许可。

acquire获取许可

查看Semaphore 获取许可的源码:

//是否可以获取许可
public boolean tryAcquire() {return sync.nonfairTryAcquireShared(1) >= 0;
}
//是否可以获取许可,并提供超时获取机制
public boolean tryAcquire(long timeout, TimeUnit unit)throws InterruptedException {return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
}
//是否可以获取多个许可,并提供超时获取机制
public boolean tryAcquire(int permits, long timeout, TimeUnit unit)throws InterruptedException {if (permits < 0) throw new IllegalArgumentException();return sync.tryAcquireSharedNanos(permits, unit.toNanos(timeout));
}
//提供一个无参获取许可方法,默认获取一个许可
public void acquire() throws InterruptedException {sync.acquireSharedInterruptibly(1);
}//不间断的获取许可,如果获取不到就阻塞
public void acquireUninterruptibly() {sync.acquireShared(1);
}
//不间断的获取多个许可,如果获取不到就阻塞
public void acquireUninterruptibly(int permits) {if (permits < 0) throw new IllegalArgumentException();sync.acquireShared(permits);
}

如源码所示,我获取许可有很多的方法。有是否可以获取许可,超时是否可以获取许可。当然还有获取许可的方法,以及阻塞获取许可的多个方法,这些方法本质上都是调用父AQS中的获取资源许可的方法,同学们可以选择自己适用的方法进行调用。

release释放许可

查看Semaphore 释放许可的源码:

//默认释放一个许可
public void release() {sync.releaseShared(1);
}
//同时释放多个许可
public void release(int permits) {if (permits < 0) throw new IllegalArgumentException();sync.releaseShared(permits);
}
//调用父AQS的释放资源的方法
public final boolean releaseShared(int arg) {if (tryReleaseShared(arg)) {doReleaseShared();return true;}return false;
}

如源码所示,Semaphore提供了多个释放许可的方法,我们可以根据实际需要选择释放许可的方法。
值得注意的是release() 方法调用了自己内部类Sync的释放资源方法,而Sync又是继承AQS阻塞队列并调用了父类doReleaseShared() 释放资源的方法。

实战演示

上面博文我们介绍了Semaphore并发类是一个同步类,它继承了AQS阻塞队列。Semaphore主要提供了acquire() 获取许可与release() 释放许可的方法,通过这两个方法我们可以实现线程并发数目的功能。下面我们简单模拟一下限制并发数目。

1、Semaphore测试类
测试类提供一个定量5的线程池,用countdownlatch 让主线程等待子线程执行完成,Semaphore保证每次只有3个线程执行。为了保证测试结果可以追溯性,我们在业务逻辑中让线程睡眠3s。

/*** Semaphore test* @author senfel* @date 2023/4/6 11:38 * @return*/
@SpringBootTest
class ConcurrentApplicationTests {/*** 日期格式*/private static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm:ss");@Testvoid testSemaphore() throws Exception {//创建线程为5的线程池ExecutorService executorService = Executors.newFixedThreadPool(5);//同时运行3个线程运行Semaphore semaphore = new Semaphore(3);//等待执行完成CountDownLatch countDownLatch = new CountDownLatch(10);for(int i = 0;i<10;i++) {executorService.execute(new Runnable() {@Overridepublic void run() {try{//获取许可semaphore.acquire();//业务逻辑executeFun();//释放许可semaphore.release();countDownLatch.countDown();}catch (Exception e){e.printStackTrace();}}});}countDownLatch.await();System.err.println("执行完成");executorService.shutdown();}/*** 执行业务方法* @author senfel* @date 2023/4/6 11:13* @return void*/private void executeFun() {try {String startTime = formatter.format(LocalDateTime.now());Thread.sleep(3000);System.err.println("当前执行线程:"+Thread.currentThread().getName()+",开始时间:"+startTime+",结束时间"+formatter.format(LocalDateTime.now()));} catch (Exception e) {e.printStackTrace();}}}

2、执行测试方法
执行testSemaphore() 方法,我们可以在控制台看到如下结果:

当前执行线程:pool-1-thread-1,开始时间:11:37:00,结束时间11:37:03
当前执行线程:pool-1-thread-3,开始时间:11:37:00,结束时间11:37:03
当前执行线程:pool-1-thread-2,开始时间:11:37:00,结束时间11:37:03
当前执行线程:pool-1-thread-2,开始时间:11:37:03,结束时间11:37:06
当前执行线程:pool-1-thread-1,开始时间:11:37:03,结束时间11:37:06
当前执行线程:pool-1-thread-3,开始时间:11:37:03,结束时间11:37:06
当前执行线程:pool-1-thread-1,开始时间:11:37:06,结束时间11:37:09
当前执行线程:pool-1-thread-4,开始时间:11:37:06,结束时间11:37:09
当前执行线程:pool-1-thread-2,开始时间:11:37:06,结束时间11:37:09
当前执行线程:pool-1-thread-5,开始时间:11:37:09,结束时间11:37:12
执行完成

根据执行结果我们可以发现每3s有3个线程执行并输出,得出结论Semaphore可以保证每次只能同时3个线程执行!!!!

总结

多线程控制并发数目工具类Semaphore内部继承AQS抽象阻塞队列,并继承了其同步获取、释放资源的方法。Semaphore提供了acquire()获取许可、release()释放许可方法,底层当然调用的是AQS内部方法来满足同步以保证限制并发线程运行数目。

相关文章:

多线程控制并发数目工具类Semaphore

文章目录前言Semaphore原理Semaphore源码解析内部继承AQS保证同步acquire获取许可release释放许可实战演示总结前言 在多线程编码过程中&#xff0c;我们会用到多线程来提升运行效率。比如我们的Executors创建线程池&#xff0c;程序尽可能的压榨CPU资源来提升我们程序吞吐量。…...

Redis篇之五大数据类型

1、五大数据类型 4.1、String&#xff08;字符串&#xff09; String是Redis最基本的类型&#xff0c;你可以理解成与Memcached一模一样的类型&#xff0c;一个key对应一个value String类型是二进制安全的。意味着Redis的string可以包含任何数据。比如jpg图片或者序列化的对象…...

Linux->文件系统磁盘文件管理

目录 1 磁盘结构 2 逻辑抽象管理磁盘 2.1 逻辑抽象 2.2 管理磁盘 2.3 补充知识 3 软硬连接 1 磁盘结构 本篇的学习需要建立在大家在脑海中有一副磁盘的结构才能进行下去&#xff0c;所以我会以图解的方式为大家简单讲解一下&#xff0c;注&#xff1a;博主对这一部分并不是…...

echarts tooltip文字太长换行

tooltip文字太长换行&#xff0c;设置了宽度也没有换行&#xff0c;加上一句&#xff1a; extraCssText: ‘max-width:300px; white-space:pre-wrap’, 没加之前是这样&#xff1a; 加上之后 extraCssText: ‘max-width:300px; white-space:pre-wrap’, tooltip: {trigger: &…...

Docker 部署Jira8.1.0

Jira与Confluence一样&#xff0c;都需要用到独立的数据库&#xff0c;对于数据库的安装我们不做介绍&#xff0c;主要介绍如何用Docker部署Jira以及对Jira进行破解的操作。 1、数据库准备 关于数据库官方文档说明&#xff1a;https://confluence.atlassian.com/adminjiraserv…...

枚举、模拟法(蓝桥杯卡片、数的分解为例)

枚举和模拟算法是计算机领域常用的两种基本算法。枚举算法是一种通过列举所有可能的情况来解决问题的方法。模拟算法则是通过模拟真实场景来解决问题。 枚举、模拟法 枚举算法是指将问题分解为一系列离散的情况&#xff0c;通过枚举所有可能的情况&#xff0c;逐一检查每种情…...

DC-DC升压变换器直流隔离高压输出稳压电源模块5v12v24v48v转50v110v150v220v250v300v350v500v

HRB 系列隔离宽电压输入高电压稳压输出 特点 效率高达 80%以上1*1英寸标准封装单电压输出稳压输出工作温度: -40℃~85℃阻燃封装&#xff0c;满足UL94-V0 要求温度特性好可直接焊在PCB 上应用 HRB 0.2~10W 系列模块电源是一种DC-DC升压变换器。该模块电源的输入电压分为&#…...

jQuery创建、添加、删除元素

一、创建元素 语法&#xff1a; $("<li></li>"); 动态的创建了一个 <li> 二、添加元素 1. 内部添加 1、element.append(内容) 把内容放入匹配元素内部最后面&#xff0c;类似原生 appendChild。 2、element.prepend(内容) 把内容放入匹…...

产品快讯丨神策数据 A/B 测试试验指标管理重磅升级

神策数据&#xff1a;为了更好地帮助企业管理试验指标&#xff0c;神策数据 A/B 测试完善了指标类型、配置方式、计算原理等&#xff0c;帮助分析师、运营同学等明确计算逻辑&#xff0c;并最大程度减少歧义以及与技术同学沟通的成本&#xff0c;以实现企业内部信息的有效统一。…...

游戏开发之Unity2021URP项目场景的构建

地面的修改和编辑&#xff1a;地面插件的使用 打开包管理器&#xff0c;在左边的包那里选择“Unity注册表”&#xff0c;在右边进行搜索“Polybrush”&#xff0c;之后选择右下角的安装 安装完之后要选择样本中的URP进行导入&#xff0c;因为我们的项目是URP渲染管线的&#x…...

数学分析:多元微积分1

卓里奇的数学分析的好处在于直接从多元函数来入手多元微积分&#xff0c;引出矩阵&#xff0c;十分自然。 紧集的概念&#xff0c;感觉直接用闭集去理解就行&#xff0c;&#xff08;对于图形学来说&#xff09;。 多元函数的极限&#xff0c;其实和单元函数并没有什么区别。 这…...

STC32G 三轮车负压电磁

文章目录前言整车效果控制思路循迹环岛处理障碍处理关键代码部分差比和以及当前速度计算角速度环速度环环岛处理障碍处理前言 年后就没怎么碰车了&#xff0c;到3月中旬换三轮了&#xff0c;可算有一点成效了&#xff0c;做个记录。 整车效果 三轮负压电磁慢速元素识别控制思…...

【编程小记】位运算 x -x 表示含义

位运算 x & -x 表示含义一、原码反码补码二、位运算 x & -x 表示含义三、最终结论一、原码反码补码 在计算机中&#xff0c;整数的数据的存储是按照补码的方式进行存储的 按照数据与0的大小&#xff0c;数据又被分为正数与负数 正数的原码反码补码相同。负数的原码&…...

信创PC利旧管理新模式,麒麟信安助力国家某部委实现高效云办公

2022年&#xff0c;国家某部委所有桌面终端均已完成信创PC替换&#xff0c;并将日常办公所需的办公Office套件、OA无纸化办公系统、即时通讯系统等全部迁移至信创PC&#xff0c;但在进行生产业务系统迁移时&#xff0c;该单位信创PC仍存在业务系统与不同芯片PC难适配、应用难兼…...

【玩转RT-Thread】RT-Thread内核宏定义详解(rtdef.h)

文章目录1.RT-Thread版本信息2.RT-Thrad基础数据类型定义3.RT-Thread基本数据类型的范围4.RT-Thread系统滴答时钟最大计数值5.RT-Thread IPC数据类型范围6.RT-Thread避免未使用变量警告7.编译器相关定义8.编译器相关定义9.RT-Thread错误码定义1.RT-Thread版本信息 /* RT-Threa…...

PDF转化器免费版有哪些?这几款办公达人们都在用

在现代办公中&#xff0c;文件的排版和格式是非常重要的&#xff0c;无论是发布通知或提交策划书、投档简历或是发表论文、宣传海报或是产品说明书等&#xff0c;我们经常使用PDF文件格式发送给他人。然而&#xff0c;很多人需要对PDF进行编辑修改&#xff0c;通常会先将其转换…...

2022MathorCup赛题B

以下所有文字均基于作者的实际经验&#xff0c;并不具有完全的合理性&#xff0c;请谨慎参考 目录 一、问题分析 &#xff08;一&#xff09;问题一 &#xff08;二&#xff09;问题二 二、预处理 &#xff08;一&#xff09;训练集预处理 &#xff08;二&#xff09;测…...

适合销售使用的CRM系统特点

销售人员抱怨CRM系统太复杂&#xff0c;这是一个很重要的问题。毕竟&#xff0c;如果系统太难使用&#xff0c;会导致CRM实用率和效率下降&#xff0c;最终影响公司的运作。在这篇文章中&#xff0c;我们来探讨当销售抱怨crm客户系统太复杂了&#xff0c;企业该如何解决。 缺少…...

项目中获取resource下文件路径的方法

String filepathrequest.getServletContext().getRealPath("/")"files\\"; 获取的当前文件在实际运行的tomcat地址目录 String path ClassUtils.getDefaultClassLoader().getResource("").getPath()"tmp/files/"; 获取的是当前文件…...

Air32F103CBT6|CCT6|KEIL-uVsion5|本地编译|STClink|(6)、Air32F103编译下载

目录 一、环境搭建 准备工作 安装支持包 二、新建工程 添加外设库支持 测试代码 三、下载烧录 一、环境搭建 准备工作 安装MDK5&#xff0c;具体方法请百度&#xff0c;安装后需要激活才能编译大文件 下载安装AIR32F103的SDK&#xff1a;luatos-soc-air32f103: Air32f…...

PROJECT MOGFACE与Dify平台集成:快速构建无需编码的AI智能体应用

PROJECT MOGFACE与Dify平台集成&#xff1a;快速构建无需编码的AI智能体应用 最近在折腾AI应用开发的朋友&#xff0c;可能都有过类似的烦恼&#xff1a;手头有一个效果不错的模型&#xff0c;比如我们团队部署的PROJECT MOGFACE&#xff0c;想把它变成一个能对外服务的、功能…...

QuickSnap:Blender三维建模效率革命,快速对齐插件让精准建模变得简单

QuickSnap&#xff1a;Blender三维建模效率革命&#xff0c;快速对齐插件让精准建模变得简单 【免费下载链接】quicksnap Blender addon to quickly snap objects/vertices/points to object origins/vertices/points 项目地址: https://gitcode.com/gh_mirrors/qu/quicksnap…...

QT 基于qcustomplot实现热力图(四):动态数据流与交互优化实战

1. 动态数据流的核心实现策略 在实时监控系统中&#xff0c;热力图的数据往往需要持续更新。我遇到过不少开发者直接粗暴地全量刷新整个数据集&#xff0c;结果界面卡顿得像老式幻灯片。这里分享三种经过实战检验的动态更新方案&#xff0c;每种都有其适用场景。 增量更新法最适…...

QuickSnap:提升三维建模效率的快速对齐工具——三维建模爱好者的精准对齐解决方案

QuickSnap&#xff1a;提升三维建模效率的快速对齐工具——三维建模爱好者的精准对齐解决方案 【免费下载链接】quicksnap Blender addon to quickly snap objects/vertices/points to object origins/vertices/points 项目地址: https://gitcode.com/gh_mirrors/qu/quicksna…...

ExcelDataReader实战指南:高效处理Excel文件3步法掌握跨格式解析

ExcelDataReader实战指南&#xff1a;高效处理Excel文件3步法掌握跨格式解析 【免费下载链接】ExcelDataReader Lightweight and fast library written in C# for reading Microsoft Excel files 项目地址: https://gitcode.com/gh_mirrors/ex/ExcelDataReader ExcelDat…...

League-Toolkit:重新定义英雄联盟游戏体验的智能助手

League-Toolkit&#xff1a;重新定义英雄联盟游戏体验的智能助手 【免费下载链接】League-Toolkit 兴趣使然的、简单易用的英雄联盟工具集。支持战绩查询、自动秒选等功能。基于 LCU API。 项目地址: https://gitcode.com/gh_mirrors/le/League-Toolkit League-Toolkit …...

深度解析Windows设备指纹伪装技术:EASY-HWID-SPOOFER内核级硬件隐私保护实现

深度解析Windows设备指纹伪装技术&#xff1a;EASY-HWID-SPOOFER内核级硬件隐私保护实现 【免费下载链接】EASY-HWID-SPOOFER 基于内核模式的硬件信息欺骗工具 项目地址: https://gitcode.com/gh_mirrors/ea/EASY-HWID-SPOOFER 在数字化时代&#xff0c;硬件隐私保护已成…...

思源宋体免费商用字体:设计师的终极开源字体解决方案

思源宋体免费商用字体&#xff1a;设计师的终极开源字体解决方案 【免费下载链接】source-han-serif-ttf Source Han Serif TTF 项目地址: https://gitcode.com/gh_mirrors/so/source-han-serif-ttf 还在为商业项目寻找高质量中文字体而烦恼吗&#xff1f;Source Han Se…...

usearch的内存泄漏自动化测试:在CI中集成泄漏检测

usearch的内存泄漏自动化测试&#xff1a;在CI中集成泄漏检测 【免费下载链接】usearch Fastest Open-Source Search & Clustering engine for Vectors & &#x1f51c; Strings in C, C, Python, JavaScript, Rust, Java, Objective-C, Swift, C#, GoLang, and Wolf…...

MagiskHide Props Config:设备属性管理的3大维度与安全检测绕过全指南

MagiskHide Props Config&#xff1a;设备属性管理的3大维度与安全检测绕过全指南 【免费下载链接】MagiskHidePropsConf This tool is now dead... 项目地址: https://gitcode.com/gh_mirrors/ma/MagiskHidePropsConf 一、价值定位&#xff1a;为什么每个root用户都需要…...