news 2026/5/23 18:07:27

深入浅出Java Condition 的await和signal机制(三)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
深入浅出Java Condition 的await和signal机制(三)

signal/signalAll 实现原理

调用 condition 的 signal 或者 signalAll 方法可以将等待队列中等待时间最长的节点移动到同步队列中,使得该节点能够有机会获得 lock。等待队列是先进先出(FIFO)的,所以等待队列的头节点必然会是等待时间最长的节点,也就是每次调用 condition 的 signal 方法都会将头节点移动到同步队列中。signal 方法源码如下:
public final void signal() { //1. 先检测当前线程是否已经获取lock if (!isHeldExclusively()) throw new IllegalMonitorStateException(); //2. 获取等待队列中第一个节点,之后的操作都是针对这个节点 Node first = firstWaiter; if (first != null) doSignal(first); }
signal 方法首先会检测当前线程是否已经获取了 lock,如果没有获取 lock 会直接抛出异常,如果获取的话,再得到等待队列的头节点,之后的 doSignal 方法也是基于该节点。doSignal 方法源码如下:
private void doSignal(Node first) { do { if ( (firstWaiter = first.nextWaiter) == null) lastWaiter = null; //1. 将头节点从等待队列中移除 first.nextWaiter = null; //2. while中transferForSignal方法对头节点做真正的处理 } while (!transferForSignal(first) && (first = firstWaiter) != null); }
具体逻辑请看注释,真正对头节点做处理的逻辑在transferForSignal方法中,该方法源码为:
final boolean transferForSignal(Node node) { /* * If cannot change waitStatus, the node has been cancelled. */ //1. 更新状态为0 if (!compareAndSetWaitStatus(node, Node.CONDITION, 0)) return false; /* * Splice onto queue and try to set waitStatus of predecessor to * indicate that thread is (probably) waiting. If cancelled or * attempt to set waitStatus fails, wake up to resync (in which * case the waitStatus can be transiently and harmlessly wrong). */ //2.将该节点移入到同步队列中去 Node p = enq(node); int ws = p.waitStatus; if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL)) LockSupport.unpark(node.thread); return true; }
关键逻辑请看注释,这段代码主要做了两件事情:
  • 1.将头节点的状态更改为 CONDITION;
  • 2.调用 enq 方法,将该节点尾插入到同步队列中,关于 enq 方法请看 AQS 的底层实现这篇文章。
调用 condition.signal 方法的前提条件是当前线程已经获取了 lock,该方法会使等待队列中的头节点即等待时间最长的那个节点移入到同步队列,而移入到同步队列后才有机会被唤醒,即从 await 方法中的LockSupport.park(this)方法中返回,才有机会让调用 await 方法的线程成功退出。
signal 执行示意图如下图:
sigllAll 与 sigal 方法的区别体现在 doSignalAll 方法上,前面我们已经知道doSignal 方法只会对等待队列的头节点进行操作,doSignalAll 的源码如下:
private void doSignalAll(Node first) { lastWaiter = firstWaiter = null; do { Node next = first.nextWaiter; first.nextWaiter = null; transferForSignal(first); first = next; } while (first != null); }
该方法会将等待队列中的每一个节点都移入到同步队列中,即“通知”当前调用condition.await()方法的每一个线程。

await 与 signal/signalAll

await、signal 和 signalAll 方法就像一个开关,控制着线程 A(等待方)和线程 B(通知方)。它们之间的关系可以用下面这幅图来说明,会更贴切:
线程 awaitThread 先通过lock.lock()方法获取锁,成功后调用 condition.await 方法进入等待队列,而另一个线程 signalThread 通过lock.lock()方法获取锁成功后调用了 condition.signal 或者 signalAll 方法,使得线程 awaitThread 能够有机会移入到同步队列中,当其他线程释放 lock 后使得线程 awaitThread 能够有机会获取 lock,从而使得线程 awaitThread 能够从 await 方法中退出并执行后续操作。如果 awaitThread 获取 lock 失败会直接进入到同步队列。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/22 0:49:54

软件工程毕业设计:8款AI工具实现高效论文写作与代码开发

文章总结表格(工具排名对比) 工具名称 核心优势 aibiye 精准降AIGC率检测,适配知网/维普等平台 aicheck 专注文本AI痕迹识别,优化人类表达风格 askpaper 快速降AI痕迹,保留学术规范 秒篇 高效处理混AIGC内容&…

作者头像 李华
网站建设 2026/5/21 6:03:38

毕业设计高效方案:8款AI工具简化论文写作与代码开发

文章总结表格(工具排名对比) 工具名称 核心优势 aibiye 精准降AIGC率检测,适配知网/维普等平台 aicheck 专注文本AI痕迹识别,优化人类表达风格 askpaper 快速降AI痕迹,保留学术规范 秒篇 高效处理混AIGC内容&…

作者头像 李华
网站建设 2026/5/23 14:01:36

信创环境下,SpringBoot如何实现百M大文件的安全上传?

大文件传输系统解决方案 背景与需求分析 作为河南某上市集团的项目负责人,我们当前面临一个关键的技术挑战:需要为政府、央企等高端客户构建一个安全可靠的大文件传输系统。经过详细的需求调研,我整理了以下核心需求点: 超大文…

作者头像 李华
网站建设 2026/5/11 22:49:28

5步解锁DLSS Swapper效能革命:游戏性能优化终极指南

5步解锁DLSS Swapper效能革命:游戏性能优化终极指南 【免费下载链接】dlss-swapper 项目地址: https://gitcode.com/GitHub_Trending/dl/dlss-swapper DLSS Swapper是一款专为游戏玩家设计的DLSS版本管理工具,能够帮助用户轻松实现动态链接库(DL…

作者头像 李华
网站建设 2026/5/6 0:37:51

比特币真的安全吗?

最终挖取比特币的核心结果基于全息确定性计算原理,在2026年比特币全网难度4.810^{39}下,使用Intel i7-12700K单线程,仅需0.002秒、13次SHA-256哈希计算,即可找到唯一的最优随机数\boldsymbol{nonce^*≈3474919327},实现…

作者头像 李华