010-从0到1带你深入并发编程:AQS核心解析:深入剖析Node内部类的源码结构与waitStatus状态机
摘要:本文深入解析了Java并发编程中AbstractQueuedSynchronizer(AQS)内部类Node的设计原理。作为AQS的核心组件,Node通过waitStatus状态机(CANCELLED/SIGNAL/CONDITION/PROPAGATE)和双向链表结构(prev/next指针)实现了高效的线程同步机制。文章详细剖析了各字段含义,重点阐述了SIGNAL状态的责任链机制和PRO
🥂(❁´◡`❁)您的点赞👍➕评论📝➕收藏⭐➕关注👀是作者创作的最大动力🤞
💖📕🎉🔥 支持我:点赞👍+收藏⭐️+留言📝+关注👀欢迎留言讨论
🔥🔥🔥(源码获取 + 调试运行 + 问题答疑)🔥🔥🔥 有兴趣可以联系我
🔥🔥🔥 文末有往期免费源码,直接领取获取(无删减,无套路)
我们常常在当下感到时间慢,觉得未来遥远,但一旦回头看,时间已经悄然流逝。对于未来,尽管如此,也应该保持一种从容的态度,相信未来仍有许多可能性等待着我们。
前言
在Java并发编程中,AbstractQueuedSynchronizer(AQS)是整个JUC并发包的基石。而理解AQS的关键,就在于深入掌握其内部类Node的设计原理。Node不仅是构成AQS同步队列和条件队列的基本单元,更是整个同步机制状态流转的核心载体。本文将带大家深入剖析Node类的源码结构,详细解析每个字段的含义,并重点探讨waitStatus状态机的工作原理。
Node类的整体结构
Node类是AQS的内部类,位于java.util.concurrent.locks.AbstractQueuedSynchronizer中。它作为AQS队列的基本节点,承担着线程封装、状态管理和队列链接的重要职责。
static final class Node {
// 节点模式常量
static final Node SHARED = new Node();
static final int CANCELLED = 1;
static final int SIGNAL = -1;
static final int CONDITION = -2;
static final int PROPAGATE = -3;
// 节点字段
volatile int waitStatus;
volatile Node prev;
volatile Node next;
volatile Thread thread;
Node nextWaiter;
// 构造方法和其他方法...
}
核心字段深度解析
1. 线程引用(thread)
volatile Thread thread字段保存了被封装在节点中的线程引用。当线程尝试获取锁失败时,AQS会将该线程包装成Node节点加入到同步队列中。
设计意义:
-
实现了线程与队列节点的绑定
-
为后续的线程唤醒提供目标对象
-
volatile修饰确保了线程间的可见性
2. 等待状态(waitStatus)
volatile int waitStatus是Node类中最重要的字段,它是一个状态机,控制着节点的生命周期和行为模式。waitStatus包含以下几种状态:
CANCELLED (1)
表示节点已被取消。当线程等待超时或被中断时,节点会进入此状态。一旦进入CANCELLED状态,节点将不再参与同步竞争。
状态迁移场景:
-
等待超时(如
tryAcquireNanos) -
线程被中断且响应中断
-
获取锁过程中发生异常
SIGNAL (-1)
这是同步队列中最常见的状态。表示当前节点的后继节点需要被唤醒。当一个节点的waitStatus为SIGNAL时,它在释放锁时有责任唤醒其后继节点。
工作机理:
// 在shouldParkAfterFailedAcquire方法中的典型应用
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;
if (ws == Node.SIGNAL)
return true; // 前驱节点为SIGNAL,当前线程可以安全阻塞
if (ws > 0) {
// 跳过已取消的前驱节点
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else {
// 将前驱节点状态设置为SIGNAL
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}
CONDITION (-2)
表示节点处于条件队列中。该状态与ConditionObject配合使用,用于实现条件变量功能。
特点:
-
节点从同步队列转移到条件队列时状态变为CONDITION
-
处于CONDITION状态的节点不会参与同步竞争
-
当条件满足时,节点从条件队列转移回同步队列,状态重置为0
PROPAGATE (-3)
仅在共享模式下使用,表示后续的acquireShared操作应该无条件传播。这个状态主要用于解决共享锁传播的竞争条件。
典型应用场景: 在doReleaseShared方法中,当头节点状态从SIGNAL变为0后,如果检测到有后续的共享节点,会将状态设置为PROPAGATE以确保传播继续。
状态0
初始状态,表示节点刚被创建还未进入任何特定状态。
3. 前驱与后继指针(prev & next)
volatile Node prev和volatile Node next构成了AQS同步队列的双向链表结构。
设计考量:
-
双向链表:便于节点的删除操作,特别是在处理CANCELLED节点时
-
volatile修饰:确保多线程环境下的内存可见性
-
CAS操作:所有指针修改都通过CAS保证原子性
4. 下一个等待条件(nextWaiter)
Node nextWaiter字段有两种用途:
-
在条件队列中,指向条件队列中的下一个等待节点
-
在同步队列中,用于标识节点模式(SHARED或EXCLUSIVE)
5. 节点模式(SHARED/EXCLUSIVE)
通过isShared()方法判断节点模式:
final boolean isShared() {
return nextWaiter == SHARED;
}
两种模式对比:
| 模式 | 标识 | 应用场景 | 唤醒策略 |
|---|---|---|---|
| 独占模式 | EXCLUSIVE | ReentrantLock等 | 只唤醒一个后继节点 |
| 共享模式 | SHARED | Semaphore、CountDownLatch等 | 传播式唤醒多个节点 |
waitStatus状态机的工作原理
状态流转图
waitStatus的状态流转是一个典型的状态机模式,理解这个状态机是掌握AQS的关键。
SIGNAL状态的核心作用
SIGNAL状态的设计体现了AQS的"责任链"思想。每个节点都对其后继节点负有通知责任:
-
设置SIGNAL:在获取锁失败后,线程会将前驱节点的waitStatus设置为SIGNAL
-
检查SIGNAL:线程在阻塞前会检查前驱节点是否为SIGNAL状态
-
履行通知义务:节点释放锁时,如果检测到SIGNAL状态,会唤醒后继节点
这种设计确保了同步队列的可靠性和高效性。
PROPAGATE状态的精妙之处
PROPAGATE状态解决了共享模式下的一种极端竞争条件。考虑以下场景:
-
线程A释放共享锁,将头节点状态从SIGNAL改为0
-
线程B此时获取共享锁成功,但在设置新头节点前被挂起
-
线程C也来释放锁,看到头节点状态为0,认为不需要传播
-
如果没有PROPAGATE状态,等待的线程可能无法被及时唤醒
PROPAGATE状态的确立确保了共享锁传播的连续性。
实际应用中的注意事项
1. 节点取消的优化处理
在节点取消时,AQS会执行清理操作,跳过所有CANCELLED状态的节点:
private void cancelAcquire(Node node) {
if (node == null)
return;
node.thread = null;
Node pred = node.prev;
while (pred.waitStatus > 0)
node.prev = pred = pred.prev;
// 详细的清理逻辑...
}
2. 条件队列与同步队列的转换
当调用Condition.signal()时,节点会从条件队列转移到同步队列,同时状态从CONDITION变为0:
final boolean transferForSignal(Node node) {
if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
return false;
Node p = enq(node);
int ws = p.waitStatus;
if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
LockSupport.unpark(node.thread);
return true;
}
总结
Node作为AQS的核心内部类,通过精巧的状态设计和指针管理,构建了一套高效、可靠的同步机制。waitStatus状态机不仅是节点状态的真实反映,更是整个AQS同步逻辑的指挥棒。深入理解Node的工作原理,对于掌握Java并发编程、诊断并发问题、甚至设计自己的同步器都具有重要意义。
通过对Node源码的剖析,我们不仅看到了Doug Lea大师精湛的设计功力,更能体会到优秀并发设计的核心思想:通过状态机的精确控制和责任链的明确划分,在保证正确性的前提下最大化性能。


「在线考试系统源码(含搭建教程)」 (无删减,无套路):🔥🔥🔥
链接:https://pan.quark.cn/s/96c4f00fdb43 提取码:WR6M
往期免费源码对应视频:
免费获取--SpringBoot+Vue宠物商城网站系统
🥂(❁´◡`❁)您的点赞👍➕评论📝➕收藏⭐➕关注👀是作者创作的最大动力🤞
💖📕🎉🔥 支持我:点赞👍+收藏⭐️+留言📝+关注👀欢迎留言讨论
🔥🔥🔥(源码 + 调试运行 + 问题答疑)
🔥🔥🔥 有兴趣可以联系我
💖学习知识需费心,
📕整理归纳更费神。
🎉源码免费人人喜,
🔥码农福利等你领!💖常来我家多看看,
📕网址:扣棣编程,
🎉感谢支持常陪伴,
🔥点赞关注别忘记!💖山高路远坑又深,
📕大军纵横任驰奔,
🎉谁敢横刀立马行?
🔥唯有点赞+关注成!
⬇⬇⬇⬇⬇⬇⬇⬇⬇⬇点击此处获取源码⬇⬇⬇⬇⬇⬇⬇⬇⬇
更多推荐


所有评论(0)