concurrentlinkedqueue 通过 jvm 垃圾回收机制和对象引用不可伪造性规避 aba 问题:每个 node 是新分配的堆对象,地址唯一且不复用;cas 比较的是引用地址而非值,地址不同则 cas 失败并重试;其基于 michael-scott 算法,依赖 gc 环境下节点不可复用的前提,无需版本号或 atomicstampedreference。

ConcurrentLinkedQueue 的入队操作不靠版本号或时间戳来解决 ABA 问题,而是利用 JVM 垃圾回收机制和对象引用的不可伪造性,从根本上规避了该问题。
Node 对象生命周期由 GC 保障唯一性
每个入队节点(Node)都是新分配在堆上的对象,其内存地址在整个生命周期内固定且不会被复用。即使某个 Node 被出队、随后被 GC 回收,JVM 也不会立即把同一地址分配给新创建的 Node —— 这意味着两个不同 Node 实例几乎不可能拥有完全相同的引用地址。
- CAS 操作的目标是 Node.next 字段,比较的是对象引用(即内存地址),不是值内容
- 即使新 Node 和旧 Node 的数据字段完全一样,它们的引用地址也不同
- CAS 失败本身即是保护:若中间有其他线程修改过 next 指针,当前 CAS 就会因地址不匹配而失败,触发重试
Michael-Scott 算法 + GC 环境的天然适配
该队列实现基于 Michael & Scott 非阻塞队列算法,并明确依赖“垃圾回收系统中不存在因节点复用导致的 ABA”这一前提。所谓“recycled nodes”在 Java GC 下实际不可发生:
- 线程持有某 Node 引用期间,该 Node 不会被 GC 回收
- 一旦 Node 从链表中脱离且无任何强引用,GC 才可能回收它;但回收后地址不会立即重用
- 因此,CAS 比较的是真实、不可伪造的堆对象身份,而非可被重复赋值的原始值
不依赖额外标记,也不用 AtomicStampedReference
不同于 AtomicInteger 或自定义链表结构,ConcurrentLinkedQueue 不需要为每个节点附加版本号或 mark 位:
- AtomicStampedReference 解决的是值类型(如 int)或可复用对象场景下的 ABA
- 而 Node 是不可变引用类型,其身份由 JVM 内存管理保证,天然具备“单次使用、地址唯一”的特性
- 源码注释直接指出:“this implementation relies on the fact that in garbage collected systems, there is no possibility of ABA problems due to recycled nodes”
它不靠修补 CAS 的语义缺陷,而是通过对象模型与运行时环境的协同设计,让 ABA 在实际执行路径中无法成立。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











