一、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()方法的底层原理的更多相关文章

  1. HashMap底层原理分析(put、get方法)

    1.HashMap底层原理分析(put.get方法) HashMap底层是通过数组加链表的结构来实现的.HashMap通过计算key的hashCode来计算hash值,只要hashCode一样,那ha ...

  2. KVO-基本使用方法-底层原理探究-自定义KVO-对容器类的监听

    书读百变,其义自见! 将KVO形式以代码实现呈现,通俗易懂,更容易掌握 :GitHub   -链接如果失效请自动搜索:https://github.com/henusjj/KVO_base 代码中有详 ...

  3. 红黑树规则,TreeSet原理,HashSet特点,什么是哈希值,HashSet底层原理,Map集合特点,Map集合遍历方法

    ==学习目标== 1.能够了解红黑树 2.能够掌握HashSet集合的特点以及使用(特点以及使用,哈希表数据结构) 3.能够掌握Map集合的特点以及使用(特点,常见方法,Map集合的遍历) 4.能够掌 ...

  4. 利用Redisson实现分布式锁及其底层原理解析

    Redis介绍 参考地址:https://blog.csdn.net/turbo_zone/article/details/83422215 redis是一个key-value存储系统.和Memcac ...

  5. iOS底层原理总结 - 探寻block的本质(一)

        面试题 block的原理是怎样的?本质是什么? __block的作用是什么?有什么使用注意点? block的属性修饰词为什么是copy?使用block有哪些使用注意? block在修改NSMu ...

  6. Java面试底层原理

    面试发现经常有些重复的面试问题,自己也应该学会记录下来,最好自己能做成笔记,在下一次面的时候说得有条不紊,深入具体,面试官想必也很开心.以下是我个人总结,请参考: HashSet底层原理:(问了大几率 ...

  7. Java8线程池ThreadPoolExecutor底层原理及其源码解析

    小侃一下 日常开发中, 或许不会直接new线程或线程池, 但这些线程相关的基础或思想是非常重要的, 参考林迪效应; 就算没有直接用到, 可能间接也用到了类似的思想或原理, 例如tomcat, jett ...

  8. 关于 ReentrantLock 中锁 lock() 和解锁 unlock() 的底层原理浅析

    关于 ReentrantLock 中锁 lock() 和解锁 unlock() 的底层原理浅析 如下代码,当我们在使用 ReentrantLock 进行加锁和解锁时,底层到底是如何帮助我们进行控制的啦 ...

  9. 【T-SQL进阶】02.理解SQL查询的底层原理

    本系列[T-SQL]主要是针对T-SQL的总结. [T-SQL基础]01.单表查询-几道sql查询题 [T-SQL基础]02.联接查询 [T-SQL基础]03.子查询 [T-SQL基础]04.表表达式 ...

  10. HashMap的底层原理

    简单说: 底层原理就是采用数组加链表: 两张图片很清晰地表明存储结构: 既然是线性数组,为什么能随机存取?这里HashMap用了一个小算法,大致是这样实现: // 存储时: int hash = ke ...

随机推荐

  1. VulNyx - System

    扫描发现 2121是ftp端口 8000 http的一个端口 6379redis端口 爆破redis的密码 爆破出来时bonjour 猜测ftp的密码和redis的密码是一样的 尝试用密码去爆出ftp ...

  2. VulNyx - Mail 靶机

    扫描靶机 发现22 和 80端口 访问80端口 发现id=1 和2 时都会有回显 dirsearch -u http://http://192.168.200.39 访问这个1 和 2的路径 发现竟然 ...

  3. Nodify学习 三:连接器

    前置 连接概述 连接是由两个点之间创建的.Source和Target依赖属性是Point类型,通常绑定到连接器的Anchor点. 基本连接 库中所有连接的基类是BaseConnection,它派生自S ...

  4. 数字先锋 | SaaS服务“拎包入住”?央企数字化转型体验感拉满!

    数字化转型已成为企业生存和发展的"必修课".作为国民经济的"压舱石""顶梁柱",国资央企正加快"上云用数赋智"步伐,引领 ...

  5. mount命令及挂载本地yum源

    mount命令 mount [-t vfstype] [-o options] device dir 其中: 1.-t vfstype 指定文件系统的类型,通常不必指定.mount 会自动选择正确的类 ...

  6. nginx 强制https

    nginx 强制https   通常有如下两种方法强制https推荐第二种,第二种更高效1.使用nginx的rewrite方法 server { listen 80; server_name xxx. ...

  7. IIS反向代理和URL重写——实现https重定向,文件类型隐藏访问重写,nodejs等服务重写等等

    一.Why? 1.先来讲一讲为什么我们要使用url重写这个东西 2.因为我学习的后端是nodejs,然后我发现nodejs一个非常让人难受的事,就是它监听端口不是80和443时,你访问网页需要输入端口 ...

  8. rust学习笔记(8)

    cargo cargo是一个用来帮助控制项目开发的工具 cargo.toml 这是一个用来管理项目的文件 首先是[package]部分 [package] name = "foo" ...

  9. Jupyter Notebook的所有文件ipynb保存下来

    前言 如果你想要保存整个 Jupyter Notebook 工作目录,包括所有笔记本和其他相关文件,最直接的方法是将整个文件夹压缩为一个 ZIP 或 TAR 文件. 下载单个文件 压缩文件夹下载 在 ...

  10. golang定时器函数 每隔几分钟执行一个函数

    延时调用 AfterFunc go function() func function() { // TODO 具体逻辑 // 每5分钟执行一次,递归调用自己 time.AfterFunc(5*time ...