AtomicMarkableReference 通过引入可翻转的布尔标记位,使 CAS 同时校验引用值和标记,从而在业务层感知 ABA 中间修改;典型做法是每次更新都翻转 mark,确保即使值恢复为 A,mark 差异也能阻止错误 CAS。

AtomicMarkableReference 是 Java 并发包中用于解决 ABA 问题并附带布尔标记的原子引用工具,它本身不直接“解决”ABA,而是通过引入额外的状态位(mark),让调用者能在 CAS 操作中同时校验引用值和标记位,从而在业务逻辑层面规避因忽略中间状态变化导致的误判。
为什么 AtomicMarkableReference 能辅助应对 ABA?
ABA 问题本质是:线程1读取到值 A → 线程2将 A 改为 B 又改回 A → 线程1执行 CAS(A→C) 成功,但实际系统状态已非初始一致。AtomicMarkableReference 将“是否被修改过”编码进 mark 位:即使引用值回到 A,只要 mark 发生翻转(比如从 false→true→false),线程1就能感知到中间发生过变更,从而拒绝错误的 CAS。
典型用法:用 mark 标记“是否被修改过”
关键在于合理设计 mark 的语义,常见策略是每次修改都翻转 mark(toggle),而非固定设为 true/false。这样能检测任意次数的中间变更:
- 初始化时:new AtomicMarkableReference<Node>(head, false)
- CAS 时传入旧引用 + 旧 mark,成功需两者同时匹配
- 更新时:获取当前 reference 和 mark → 计算新 reference(如新节点)→ 新 mark = !oldMark
- 避免 mark 静态赋值(如总设为 true),否则失去区分能力
结合栈或链表实现无锁结构的示例逻辑
以无锁栈 push 为例,防止 ABA 导致节点复用错误:
立即学习“Java免费学习笔记(深入)”;
- 读取当前 top 节点 ref 和 mark
- 构造新节点 newTop,指向原 top
- 尝试 cas(ref, newTop, mark, !mark) —— 要求 ref 和 mark 同时未变
- 失败则重试,成功则 newTop 成为新栈顶,且 mark 翻转记录了一次变更
此时即使原 top 被弹出又压入(ABA),其 mark 已不同,CAS 失败,避免错误链接。
注意边界与局限
AtomicMarkableReference 提供的是 1 位状态,适用场景有限:
- 仅支持布尔语义,无法记录修改次数或原因;需要多状态时考虑 AtomicStampedReference
- mark 翻转需由业务主动维护,库本身不自动管理
- 仍需配合正确的算法设计(如节点不可重用、内存安全回收等),单靠 mark 不能替代完整无锁编程实践
- GC 友好:引用和 mark 都是原子更新,无额外对象分配


















