Semaphore.release()方法的底层原理
一、release() 方法代码解析
当调用 release() 方法时,实际调用的是 AQS 的 releaseShared(1) 方法。以下是其详细工作流程:
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
doReleaseShared();
return true;
}
return false;
}
1、Semaphore.release()
public void release() {
sync.releaseShared(1); // 调用 AQS 的共享模式方法
}
2、AQS.releaseShared(int arg)
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) { // 尝试释放许可
doReleaseShared(); // 唤醒等待线程
return true;
}
return false;
}
3、Semaphore.tryReleaseShared(int releases)
protected boolean tryReleaseShared(int releases) {
for (;;) {
int current = getState(); // 当前剩余许可数
int next = current + releases; // 计算新的许可数
if (next < current) {
throw new Error("Maximum permit count exceeded"); // 防止溢出
}
if (compareAndSetState(current, next)) { // CAS 更新 state
return true; // 成功释放许可
}
}
}
4、AQS.doReleaseShared()
private void doReleaseShared() {
for (;;) {
Node h = head; // 获取队列头节点
if (h != null && h != tail) { // 队列不为空
int ws = h.waitStatus;
if (ws == Node.SIGNAL) { // 需要唤醒后继节点
if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0)) {
continue; // CAS 失败,重试
}
unparkSuccessor(h); // 唤醒后继节点
} else if (ws == 0 && !compareAndSetWaitStatus(h, 0, Node.PROPAGATE)) {
continue; // CAS 失败,重试
}
}
if (h == head) { // 头节点未变化,退出循环
break;
}
}
}
二、release() 的工作流程
当调用 release() 方法时,实际调用的是 AQS 的 releaseShared(1) 方法。以下是其详细工作流程:
(1)、增加许可数
1、调用 tryReleaseShared(arg):
tryReleaseShared(arg) 是 AQS 的模板方法,由 Semaphore 实现。
在 Semaphore 中,tryReleaseShared(arg) 的逻辑是通过 int next = current + releases; 操作将 state 增加 1。
2、CAS 操作:
使用 compareAndSetState(current, next) 方法原子性地更新 state 变量。
如果 CAS 成功,表示线程成功释放许可;否则,重试。
(2)、唤醒等待线程
1、检查等待队列:
如果 CLH 队列中有等待的线程,AQS 会唤醒队列中的第一个有效节点(线程)。
被唤醒的线程会重新尝试获取许可。
2、传播唤醒:
- 在共享模式下,AQS 会传播唤醒信号,确保所有等待的线程都有机会获取许可。
Semaphore.release()方法的底层原理的更多相关文章
- HashMap底层原理分析(put、get方法)
1.HashMap底层原理分析(put.get方法) HashMap底层是通过数组加链表的结构来实现的.HashMap通过计算key的hashCode来计算hash值,只要hashCode一样,那ha ...
- KVO-基本使用方法-底层原理探究-自定义KVO-对容器类的监听
书读百变,其义自见! 将KVO形式以代码实现呈现,通俗易懂,更容易掌握 :GitHub -链接如果失效请自动搜索:https://github.com/henusjj/KVO_base 代码中有详 ...
- 红黑树规则,TreeSet原理,HashSet特点,什么是哈希值,HashSet底层原理,Map集合特点,Map集合遍历方法
==学习目标== 1.能够了解红黑树 2.能够掌握HashSet集合的特点以及使用(特点以及使用,哈希表数据结构) 3.能够掌握Map集合的特点以及使用(特点,常见方法,Map集合的遍历) 4.能够掌 ...
- 利用Redisson实现分布式锁及其底层原理解析
Redis介绍 参考地址:https://blog.csdn.net/turbo_zone/article/details/83422215 redis是一个key-value存储系统.和Memcac ...
- iOS底层原理总结 - 探寻block的本质(一)
面试题 block的原理是怎样的?本质是什么? __block的作用是什么?有什么使用注意点? block的属性修饰词为什么是copy?使用block有哪些使用注意? block在修改NSMu ...
- Java面试底层原理
面试发现经常有些重复的面试问题,自己也应该学会记录下来,最好自己能做成笔记,在下一次面的时候说得有条不紊,深入具体,面试官想必也很开心.以下是我个人总结,请参考: HashSet底层原理:(问了大几率 ...
- Java8线程池ThreadPoolExecutor底层原理及其源码解析
小侃一下 日常开发中, 或许不会直接new线程或线程池, 但这些线程相关的基础或思想是非常重要的, 参考林迪效应; 就算没有直接用到, 可能间接也用到了类似的思想或原理, 例如tomcat, jett ...
- 关于 ReentrantLock 中锁 lock() 和解锁 unlock() 的底层原理浅析
关于 ReentrantLock 中锁 lock() 和解锁 unlock() 的底层原理浅析 如下代码,当我们在使用 ReentrantLock 进行加锁和解锁时,底层到底是如何帮助我们进行控制的啦 ...
- 【T-SQL进阶】02.理解SQL查询的底层原理
本系列[T-SQL]主要是针对T-SQL的总结. [T-SQL基础]01.单表查询-几道sql查询题 [T-SQL基础]02.联接查询 [T-SQL基础]03.子查询 [T-SQL基础]04.表表达式 ...
- HashMap的底层原理
简单说: 底层原理就是采用数组加链表: 两张图片很清晰地表明存储结构: 既然是线性数组,为什么能随机存取?这里HashMap用了一个小算法,大致是这样实现: // 存储时: int hash = ke ...
随机推荐
- Superset 稀奇古怪的bug
1.filterbox 及 native filter 等组件里面,日期筛选器下拉框,显示的不是日期格式,而是时间戳格式,如: 解决方法: 修改superset\utils\core.py 里面的js ...
- 学习shamir秘密分享
介绍 1979年Shamir在下文提出基于拉格朗日插值多项式的\((r,n)\)秘密共享方案(\(0<r \leq n\)).秘密拥有者通过构建一元多项式将秘密分为\(n\)份,接收方收集大于等 ...
- cmake-2
似懂非懂,一定要搞懂基础的,剩下的边做边学,从案例中入手. 有关cmake的介绍,请参考: 1.https://www.cnblogs.com/pam-sh/p/13885959.html 2.htt ...
- Shiftdel walkthrough Intermediate
点击查看代码 nmap -p- -A 192.168.167.174 Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-11-12 00:09 UT ...
- java中数组和字符串
数组 数组的声明方式: 类型[] 变量; 数组的创建方式: new 类型[数组长度] 数组的简单声明并且赋值 // 声明一个数组,它的长度是3 String[] arrs= new String[3] ...
- 1.Vue3 配置开发-测试环境
1.根目录新建.env.testing..env.donline文件 2.package.json=>scripts中配置 "start": "vue-cli-se ...
- MOS管选型
MOS管基本参数 MOS管(Metal-Oxide-Semiconductor Field-Effect Transistor, MOSFET)作为开关元件的应用非常广泛,其开关特性与三极管相比有所不 ...
- ARC101E题解
前言 此片题解大致按照笔者做题思路进行讲解. 简要题意 有一棵树,树上有偶数个节点.你需要给这些点两两配对,一组已经配对的点会将两点之间的树边进行一次覆盖.一组合法方案需要满足树上所有边都被覆盖至少一 ...
- rabbitmq的基本使用
使用MQ的三大作用:1.同步变异步2.流量削峰3.解耦降低服务间的耦合性要不要使用MQ,需不需要使用MQ依据项目的需要做选择. 使用场景: 例如:注册用户时候,发送激活邮件.监控应用中抛出的异常,邮件 ...
- Java Properties配置文件和XML配置文件读取
一.properties类读取配置文件 1.从项目中读取properties配置文件,新建一个main程序,对应位置建立一个名称为config.properties配置文件,随意放置一些键值对.IDE ...