AtomicMarkableReference通过“引用+布尔标记”原子封装解决简单ABA问题:即使引用从A→B→A,只要标记被翻转(如false→true),compareAndSet因标记不匹配而失败,从而暴露中间修改;适用于双态场景,但无法区分多次ABA。

AtomicMarkableReference 通过“引用 + 布尔标记”双字段原子更新,从根本上避开 ABA 问题——它不依赖值本身是否变化,而是用额外的标记位记录逻辑状态变更,哪怕引用地址回到旧值,只要标记翻转过,就能被检测出来。
为什么布尔标记能防 ABA?
ABA 本质是:某个引用从 A → B → A,单看引用值没变,但中间已发生修改。而 AtomicMarkableReference 把一次“有效修改”定义为“引用或标记至少一个变了”。即使引用绕回原对象,只要你在关键节点翻转标记(比如从 false 改成 true),compareAndSet 就会失败,因为期望的标记值已不匹配。
典型用法:用标记表示“是否已被处理”
比如实现一个带“已删除”语义的无锁栈节点:
- 初始时,栈顶为
node,标记为 false(表示活跃) - 删除时,不真正断开引用,而是用 compareAndSet 尝试把标记设为 true
- 后续任何 CAS 操作都必须同时匹配当前引用和标记;若别人已将标记改为 true,你的“重置为 false”操作就会失败
关键操作要传入“期望标记”,不能只看引用
所有原子方法(如 compareAndSet、weakCompareAndSet)都要求传入:compareAndSet(旧引用, 新引用, 旧标记, 新标记)
这意味着:哪怕旧引用和新引用相同(A→A),只要旧标记和新标记不同(false→true),就构成一次有效状态跃迁,且能被其他线程感知并拦截重复操作。
注意标记不是版本号,但可模拟简单版本语义
布尔标记只有两个状态,不能记录修改次数。如果需要更强的版本控制(如区分 A→B→A→B),应改用 AtomicStampedReference(带整数戳)。但对多数场景——比如“未删除/已删除”、“未初始化/已初始化”、“未提交/已提交”——单个布尔标记足够清晰且开销更低。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











