news 2026/4/3 2:08:37

深入浅出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/3/27 1:13:36

LeetCode 跳跃游戏 II 最优解法:贪心算法

在刷LeetCode的过程中,跳跃游戏 II(Jump Game II) 是一道经典的贪心算法题目,要求我们以最少的跳跃次数到达数组的最后一个位置。这篇文章将详细讲解如何用贪心思想高效解决这个问题,全程使用Java代码实现,…

作者头像 李华
网站建设 2026/3/24 7:41:55

智能创作工具:10款AIGC免费与付费版本详细测评

�� 10大降AIGC平台核心对比速览 排名 工具名称 降AIGC效率 适用场景 免费/付费 1 askpaper ⭐⭐⭐⭐⭐ 学术论文精准降AI 付费 2 秒篇 ⭐⭐⭐⭐⭐ 快速降AIGC降重 付费 3 Aibiye ⭐⭐⭐⭐ 多学科论文降AI 付费 4 Aicheck ⭐⭐⭐⭐…

作者头像 李华
网站建设 2026/3/31 6:21:14

软件工程毕业设计提速:8款AI工具辅助论文与代码工作

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

作者头像 李华
网站建设 2026/4/2 19:38:23

政务数据治理实践:从架构搭建到价值释放的全流程探索

在数字化浪潮下,数据已成为驱动各行业发展的核心生产要素,政务领域的数据资源因其权威性、基础性特征,更是在城市治理、公共服务优化等场景中发挥着关键作用。如何让分散的政务数据实现高效汇聚、合规治理与价值释放,成为当前数字…

作者头像 李华
网站建设 2026/3/29 0:31:28

毕业设计加速器:8款AI工具优化论文撰写与编程任务

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

作者头像 李华