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

JUC并发编程之Semaphore-应用与深度源码剖析

目录

JUC并发编程之Semaphore-应用与深度源码剖析

1. Semaphore 是什么?

2.怎么使用Semaphore?

2.1构造方法

2.2 重要方法

2.3 基本使用

需求场景

基础版代码实现

tryAcquire()引入代码实现

acquireUninterruptibly(),acquire()对比代码实现

 3.源码剖析【重点】

底层结构图:

思路总结:

semaphore.acquire():

semaphore.release():


 JUC并发编程之Semaphore-应用与深度源码剖析

1. Semaphore 是什么?

Semaphore字面意思是信号量的意思,它的作用就是控制访问特定资源的线程数目,底层依赖AQS的状态State,是在生产当中比较常用的一个工具类。

2.怎么使用Semaphore?

2.1构造方法

public Semaphore(int permits)
public Semaphore(int permits, boolean fair)

permits表示许可线程的数量

fair表示公平性,如果这个设为true的话,下一次执行的线程就会是等待最久的线程

2.2 重要方法

public void acquire() throws InterruptedException
public void release()
tryAcquire(int args,long timeout, TimeUnit unit)
  • acquire() 表示阻塞并获取许可
  • release() 表示释放许可

2.3 基本使用

需求场景

资源访问,服务限流Hystrix里面限流底层就是基于信号量的方式,如图所示:

基础版代码实现

/*** @Description: TODO* @Author: etcEriksen* @Date: 2023/3/7**/
@Slf4j
@SuppressWarnings({"all"})
public class SemaphoreRunner {public static void main(String[] args) {//构造参数为:2,表示的含义为:该Semaphore所带有的总公共资源为2Semaphore semaphore = new Semaphore(2);for (int i = 0; i < 10; i++) {new Thread(new Task(semaphore,"leomessi:"+i)).start();}}static class Task extends Thread {Semaphore semaphore ;public Task(Semaphore semaphore,String tname) {super(tname) ;this.semaphore = semaphore ;}@Overridepublic void run() {try {//semaphore.acquireUninterruptibly();semaphore.acquire(2);//获取2个公共资源才可以通过一个线程 【带有中断抛出异常的机制】log.info(Thread.currentThread().getName()+":aquire at time:" + System.currentTimeMillis()) ;Thread.sleep(5000) ;semaphore.release(2) ;//归还公共资源,并且归还的公共资源数量要和一个线程通过时获取的公共资源数量要持平} catch (Exception e) {e.printStackTrace();}}public void fallback() {log.info("降级");}}}

代码分析:

运行结果:

tryAcquire()引入代码实现

/*** @Description: TODO* @Author: etcEriksen* @Date: 2023/3/7**/
@Slf4j
@SuppressWarnings({"all"})
public class SemaphoreRunner {public static void main(String[] args) {//构造参数为:2,表示的含义为:该Semaphore所带有的总公共资源为2Semaphore semaphore = new Semaphore(2);for (int i = 0; i < 10; i++) {new Thread(new Task(semaphore,"leomessi:"+i)).start();}}static class Task extends Thread {Semaphore semaphore ;public Task(Semaphore semaphore,String tname) {super(tname) ;this.semaphore = semaphore ;}@Overridepublic void run() {try {
//                //semaphore.acquireUninterruptibly();// semaphore.acquire();//获取2个公共资源才可以通过一个线程 【带有中断抛出异常的机制】
//                Thread.sleep(5000) ;
//                semaphore.release(2) ;//归还公共资源,并且归还的公共资源数量要和一个线程通过时获取的公共资源数量要持平if (semaphore.tryAcquire(500, TimeUnit.MILLISECONDS)) {log.info(Thread.currentThread().getName()+":aquire at time:" + System.currentTimeMillis()) ;Thread.sleep(5000);semaphore.release();//释放公共资源} else {//如果500毫秒线程还没有获取到相对应的2个公共资源,那么降级处理fallback();}} catch (Exception e) {e.printStackTrace();}}public void fallback() {log.info("降级");}}}

分析代码:这里结合了降级处理

运行结果:

acquireUninterruptibly(),acquire()对比代码实现

acquire():当线程被中断后,会抛出InterruptException异常。

acquireUninterruptibly():当线程被中断后,不会抛出异常。

acquireUninterruptibly(): 结合代码分析

运行结果

 acquire():结合代码分析

 运行结果:

 3.源码剖析【重点】

底层结构图:

ProcessOn Flowchart

思路总结:

初始化Semaphore对象时指定总资源数量,多个线程进来时会去竞争该公共资源,但是在公平锁的情况下,会维护一个CLH阻塞队列,该队列为公平队列,从前往后进行唤醒获取公共资源。当公共资源不够当前线程使用时或CLH阻塞队列存在节点时,新进来的线程对象都会被封装为Node节点加入到CLH阻塞队列的尾部,公平等待时机。非公平锁时,与之正好相反。

semaphore.acquire():

 1.

2.

 3.

 acquireSharedInterruptibly()调用的tryAcquireShared解析:

acquireSharedInterruptibly()调用的doAcquireSharedInterruptibly解析:

 很多相同的源码在之前的源码分析中都详细介绍了,所以这里只记录新出现的源码思路:

注:doAcquireSharedInterruptibly方法调用的tryAcquireShared方法

4.应用层调用Interrupt()方法

应用层的interrupt()中断方法调用后,底层park阻塞被中断,那么继续向下执行代码:

interrupt()方法给当前线程打上中断标识啦,所以调用interrupted()方法时返回true并且消除中断标识。

semaphore.release():

该方法后之前源码分析的lock.unlock()的思路基本一致。简略记录:

1.

2.

3.

 

 

相关文章:

JUC并发编程之Semaphore-应用与深度源码剖析

目录 JUC并发编程之Semaphore-应用与深度源码剖析 1. Semaphore 是什么&#xff1f; 2.怎么使用Semaphore&#xff1f; 2.1构造方法 2.2 重要方法 2.3 基本使用 需求场景 基础版代码实现 tryAcquire()引入代码实现 acquireUninterruptibly(),acquire()对比代码实现 3.…...

JWT详细介绍使用

一、JWT介绍 JWT是JSON Web Token的缩写&#xff0c;即JSON Web令牌&#xff0c;是一种自包含令牌。 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准。 JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息&#xff0c;以便于从资源服务…...

C/C++开发,无可避免的多线程(篇六).线程池封装类

一、线程池概念 线程池是一种多线程处理方式&#xff0c;它包含一个线程工作队列和一个任务队列。当有任务需要处理时&#xff0c;线程池会从线程工作队列中取出一个空闲线程来处理任务&#xff0c;如果线程工作队列中没有空闲线程&#xff0c;则任务会被放入任务队列中等待处理…...

HIVE中如何实现针对IPv6 CIDR的查询

Hive默认情况下不支持IPv6 CIDR查询,因为IPv6 CIDR查询需要使用一些额外的函数。 但是可以通过使用UDF(用户自定义函数)来实现这一点。 IPv6 CIDR表示为网络地址/前缀长度,其中网络地址是一个IPv6地址,前缀长度是一个介于0和128之间的整数,表示网络地址中前多少位是网络…...

【微信小程序】-- 生命周期(二十八)

&#x1f48c; 所属专栏&#xff1a;【微信小程序开发教程】 &#x1f600; 作  者&#xff1a;我是夜阑的狗&#x1f436; &#x1f680; 个人简介&#xff1a;一个正在努力学技术的CV工程师&#xff0c;专注基础和实战分享 &#xff0c;欢迎咨询&#xff01; &…...

Kafka 概述

Kafka 概述Broker消费者Kafka 属于分布式的消息引擎系统&#xff0c;主要功能 &#xff1a;提供一套完备的消息发布与订阅解决方案 生产者和消费者都是客户端&#xff08;Clients&#xff09;&#xff1a; 生产者&#xff08;Producer&#xff09;&#xff1a;向主题发布消息…...

详解Java8中如何通过方法引用获取属性名/::的使用

在我们开发过程中常常有一个需求&#xff0c;就是要知道实体类中Getter方法对应的属性名称&#xff08;Field Name&#xff09;&#xff0c;例如实体类属性到数据库字段的映射&#xff0c;我们常常是硬编码指定 属性名&#xff0c;这种硬编码有两个缺点。 1、编码效率低&#x…...

0106广度优先搜索和最短路径-无向图-数据结构和算法(Java)

1 单点最短路径 单点最短路径。 给定一幅图和一个起点s&#xff0c;回答“从s到给定目的顶点v是否存在一条路径&#xff1f;如果有&#xff0c;找出其中最短的那条&#xff08;所含边数最少&#xff09;。“等类似问题。 深度优先搜索在这个问题上没有什么作为&#xff0c;因为…...

僵尸(Zombie)进程

文章目录1.僵尸进程2.产生僵尸进程的原因3.利用 wait 函数销毁僵尸进程4.使用 waitpid 函数销毁僵尸进程1.僵尸进程 进程完成工作后&#xff08;执行完 main 函数中的程序后&#xff09;应被销毁&#xff0c;但有时这些进程将变成僵尸进程&#xff0c;占用系统中的重要资源。这…...

JS实现:有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问每个月的兔子总数为多少?

题目&#xff1a;有一对兔子&#xff0c;从出生后第3个月起每个月都生一对兔子&#xff0c;小兔子长到第三个月后每个月又生一对兔子&#xff0c;假如兔子都不死&#xff0c;问每个月的兔子总数为多少&#xff1f; 数列是 1,1,2,3,5,8,13,21....观察可以看出来从第三个数字开始…...

Verilog如何编写一个基础的Testbench

本文将讲述如何使用Verilog 编写一个基础的测试脚本&#xff08;testbench&#xff09;。在考虑一些关键概念之前&#xff0c;先来看看testbench的架构是什么样的。架构包括建模时间、initial块&#xff08;initial block&#xff09;和任务&#xff08;task&#xff09;。此文…...

基于JavaEE社区物业管理系统开发与实现(附源码资料)

文章目录1. 适用人群2. 你将收获3.项目简介4.技术栈5.测试账号6.部分功能模块展示6.1.管理员6.2.业主1. 适用人群 本课程主要是针对计算机专业相关正在做毕业设计或者是需要实战项目的Java开发学习者。 2. 你将收获 提供&#xff1a;项目源码、项目文档、数据库脚本、软件工…...

问一下ChatGPT:DIKW金字塔模型

经常看到这张DIKW金字塔模型图&#xff0c;还看到感觉有点过份解读的图&#xff0c;后面又加上了insight&#xff0c;impact等内容。 Data&#xff1a;是数据&#xff0c;零散的、无规则的呈现到人们眼前&#xff0c;如果你只看到这些数字&#xff0c;如果没有强大的知识背景&a…...

javaScript基础面试题 ---闭包

闭包1、闭包是什么&#xff1f;2、闭包可以解决什么问题&#xff1f;3、闭包的缺点1、闭包是什么&#xff1f; 闭包是一个函数加上到创建这个函数的作用域的链接&#xff0c;就是一个作用域可以访问到另一个作用域的变量&#xff0c;闭包‘关闭’了函数的自由变量 function f…...

如何自定义您的网站实时聊天图标

实时聊天图标是您网站上的一个按钮&#xff0c;可在访问者单击时打开实时聊天。它代表了您的企业与客户沟通的门户。这是您的网站访问者与您联系、提出问题和接收个性化推荐的一种方式&#xff0c;聊天图标的设计最好是简单且引人入胜&#xff0c;个性化的图标往往更能提现企业…...

Vue侦听器Watch

31. Vue侦听器Watch 1. 定义 Watch是Vue.js提供的一个观察者模式&#xff0c;用于监听数据的变化并执行相应的回调函数。虽然计算属性Computed在大多数情况下更合适&#xff0c;但有时也需要一个自定义的侦听器Watch。因为在有些情况下&#xff0c;我们需要在状态变化时执行一…...

云快充研发中心平台架构师谈云原生稳定性建设之路

作者&#xff1a;吕周洋 大家好&#xff0c;我是来自云快充研发中心的平台架构师吕周洋&#xff0c;今天我给大家分享云快充云原生稳定性之路。 点击查看&#xff1a;云快充研发中心平台架构师 吕周洋&#xff1a;云快充云原生稳定性治理之路 云快充成立于2016年&#xff0c…...

ENVI IDL学习笔记之基本操作

前言ENVI IDL&#xff08;交互式数据语言&#xff09;是一个通用的科学计算包&#xff0c;它提供了一套数学函数、数据分析工具&#xff0c;以及一些科学可视化和动画工具。IDL 是 ENVI 图像处理和分析软件的基础&#xff0c;可用于编写脚本并自动执行许多使用 ENVI 图形用户界…...

多线程面试题

1. Sychronized的锁升级过程是怎样的&#xff1f; 2. Tomcat 中为什么要使用自定义类加载器&#xff1f; 3. 说说对线程安全的理解 4. 对守护线程的理解 5. 并发、并行、串行之间的区别 6. Java死锁如何避免&#xff1f; 7. 谈谈你对AQS的理解&#xff0c;AQS如何实现可重入锁&…...

YARN运行流程

YARN是Hadoop资源管理器&#xff0c;他是一个通用资源管理平台和调度平台&#xff0c;可为上层应用提供统一的资源管理和调度&#xff0c;MapReduce等运算程序则相当于运行于操作系统上的应用程序&#xff0c;YARN为这些程序提供运算所需的资源内存、cpu。 YARN并不清楚用户提…...

LuatOS扩展库API——【airlbs 】airlbs 定位服务

LuatOS 是物联网终端开发的常用工具&#xff0c;为轻量级嵌入式 Lua 脚本运行框架兼实时系统&#xff0c;基于 Lua 5.3 深度优化&#xff0c;适配 4G-Cat.1、MCU 等物联网终端硬件。其以 Lua 脚本开发&#xff0c;采用协程多任务架构&#xff0c;配套完善开发资源&#xff0c;含…...

ViGEmBus虚拟手柄驱动:Windows系统控制器仿真解决方案与开发者指南

ViGEmBus虚拟手柄驱动&#xff1a;Windows系统控制器仿真解决方案与开发者指南 【免费下载链接】ViGEmBus Windows kernel-mode driver emulating well-known USB game controllers. 项目地址: https://gitcode.com/gh_mirrors/vi/ViGEmBus 核心价值解析&#xff1a;重新…...

​答辩 PPT「懒人救星」实测:paperxie AI 一键把论文转成答辩稿,再也不用熬夜排版​

paperxie-免费查重复率aigc检测/开题报告/毕业论文/智能排版/文献综述/AIPPThttps://www.paperxie.cn/ppt/createhttps://www.paperxie.cn/ppt/create paperxie-免费查重复率aigc检测/开题报告/毕业论文/智能排版/文献综述/AIPPT 谁本科答辩没栽在 PPT 上&#xff1f;万字论文…...

OpenClaw+Qwen3.5-9B:3步搭建自动化内容审核系统

OpenClawQwen3.5-9B&#xff1a;3步搭建自动化内容审核系统 1. 为什么选择OpenClaw做内容审核&#xff1f; 去年运营一个技术社区时&#xff0c;我每天要花2小时手动审核用户提交的内容。直到发现OpenClaw这个开源自动化框架&#xff0c;配合Qwen3.5-9B的多模态能力&#xff…...

实战剖析:利用EFDD与VeraCrypt破解加密磁盘文件

1. 加密磁盘破解的核心原理 当你面对一个加密的VeraCrypt容器时&#xff0c;第一反应可能是"这数据还能救吗&#xff1f;"。我处理过几十起类似案例&#xff0c;可以明确告诉你&#xff1a;只要获取到内存转储文件&#xff0c;就有很大概率能还原出加密密钥。这里的关…...

vLLM-v0.17.1详细步骤:SSH远程部署+Jupyter可视化结果分析全流程

vLLM-v0.17.1详细步骤&#xff1a;SSH远程部署Jupyter可视化结果分析全流程 1. vLLM框架简介 vLLM是一个专注于大语言模型(LLM)推理和服务的高性能开源库。这个项目最初由加州大学伯克利分校的天空计算实验室开发&#xff0c;现在已经发展成为一个活跃的社区驱动项目&#xf…...

NaViL-9B图文问答教程:从单图理解到多图对比分析的进阶用法

NaViL-9B图文问答教程&#xff1a;从单图理解到多图对比分析的进阶用法 1. 认识NaViL-9B多模态模型 NaViL-9B是一款原生支持多模态交互的大语言模型&#xff0c;能够同时处理文本和图像输入。与传统的纯文本模型不同&#xff0c;它可以直接"看懂"图片内容&#xff…...

STM32串口通信实战:从零配置USART到数据收发(附代码)

STM32串口通信实战&#xff1a;从零配置USART到数据收发&#xff08;附代码&#xff09; 第一次接触STM32的串口通信时&#xff0c;我被各种术语搞得晕头转向——波特率、数据位、停止位、校验位...更别提那些看起来像天书一样的寄存器配置了。直到在项目中被逼着用USART和传感…...

UVM避坑指南:为什么你的sequence卡住了?item_done没调用的常见问题排查

UVM验证中的sequence卡死问题&#xff1a;item_done未调用的深度排查手册 在芯片验证领域&#xff0c;UVM框架的sequence机制堪称验证工程师的"瑞士军刀"&#xff0c;但这把利器偶尔也会出现卡壳的情况。想象一下这样的场景&#xff1a;你的验证环境已经运行了数百个…...

DeEAR语音情感识别入门必看:为何唤醒度比‘情绪极性’更能反映真实交互状态?

DeEAR语音情感识别入门必看&#xff1a;为何唤醒度比‘情绪极性’更能反映真实交互状态&#xff1f; 如果你用过一些语音助手&#xff0c;或者跟客服机器人打过交道&#xff0c;可能会发现一个有趣的现象&#xff1a;有时候系统能识别出你“生气”了&#xff0c;但它的回应方式…...