AQS通过CAS原子操作与自旋重试保障tail指针更新安全,入队采用“先拼后连”双阶段机制,节点构造与指针绑定分离,并以volatile确保状态可见性。

AQS 通过CAS(Compare-And-Swap)原子操作 + 自旋重试机制,确保多线程并发修改队列指针(如 tail)时不会丢节点。
tail 指针更新必须用 CAS
AQS 的队列尾指针 tail 是 volatile 修饰的,但仅靠 volatile 无法保证“读-改-写”的原子性。因此所有对 tail 的变更都封装在 CAS 方法中:
-
compareAndSetTail(Node expect, Node update):只有当当前tail值等于预期值时,才将其设为新节点;否则失败返回 false - 该方法由 Unsafe 类底层调用 CPU 级指令实现,不可中断、不可分割
入队操作采用“先拼后连”双阶段保障
AQS 的 addWaiter 并非一步完成,而是分两层兜底:
- 快速路径:若当前
tail非空,先尝试 CAS 设置新节点为 tail;成功则再补上前驱的next指针 - 慢速路径(
enq):若 CAS 失败(说明有其他线程刚更新了 tail),就进入自旋循环,不断重试直到插入成功 - 即使多个线程同时执行
enq,每次循环都重新读取最新tail,避免基于过期值操作
节点构造与指针绑定严格分离
每个 Node 在创建时就绑定当前线程,并设置好 prev 和 waitStatus,但 next 指针不立即赋值:
- 新节点只负责设置自己的
prev,并尝试成为新的tail - 前驱节点的
next由成功更新tail的线程负责补全(如pred.next = node) - 即使某次补全因线程调度未及时执行,也不影响节点入队完整性——因为
tail已指向它,后续唤醒逻辑会从tail反向遍历
没有锁,但有状态可见性兜底
所有关键字段(state、head、tail、Node.waitStatus、Node.thread)均用 volatile 修饰:
- 保证任意线程对这些字段的写,对其他线程立即可见
- 配合 CAS,形成“原子写 + 强可见”的组合,消除因缓存不一致导致的节点丢失或误判
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











