atomicmarkablereference 是 java 中用于原子性更新对象引用及关联布尔标记的类,解决分开操作导致的引用与标记错位问题,通过打包二者实现 cas 原子验证与更新。

AtomicMarkableReference 是 Java 并发包(java.util.concurrent.atomic)中一个专门用于“对象引用 + 布尔标记”原子性联合更新的类。它解决的核心问题是:当需要同时更新一个引用和一个关联的布尔状态(比如“是否已删除”、“是否已初始化”、“是否被标记”)时,避免因分开操作导致的竞态条件。
为什么不能只用 AtomicReference + 单独 boolean?
如果用 AtomicReference<t></t> 存对象,再用一个独立的 AtomicBoolean 存标记,两者更新不是原子的。例如:
- 线程 A 读到引用为 X、标记为 false;
- 线程 B 同时将引用改为 Y、标记设为 true;
- 线程 A 接着把引用设为 Z,但没改标记 —— 此时引用和标记就“错位”了(Z 对应 false,但业务上应是 Z+true)。
AtomicMarkableReference 把引用和标记打包成一个不可分割的单元,CAS 操作能一次性验证并更新二者。
基本用法:构造、读取与 CAS 更新
创建时需指定初始引用和初始标记:
AtomicMarkableReference获取当前值和标记:
-
ref.getReference()→ 返回当前引用(如 "init") -
ref.isMarked()→ 返回当前标记(boolean) -
ref.get(new boolean[1])→ 一次性获取引用,并把标记写入传入的数组第 0 位(推荐用于 CAS 前读取)
CAS 更新(最常用):
boolean success = ref.compareAndSet(oldRef, newRef, oldMark, newMark);只有当当前引用 == oldRef 且当前标记 == oldMark 时,才原子地设为 newRef 和 newMark,返回是否成功。
典型场景:带标记的节点回收或状态切换
比如实现一个简单的“惰性删除”链表节点:
- 节点本身不真正从链表移除,而是用
AtomicMarkableReference<node></node>标记“已逻辑删除”; - 后续遍历时跳过 marked == true 的节点;
- GC 可安全回收,因为标记和引用绑定,不会出现“引用已变但标记未同步”的误判。
又如资源初始化控制:
AtomicMarkableReference// 尝试初始化一次
Connection c = new Connection();
if (connRef.compareAndSet(null, c, false, true)) {
// 成功设置为 c + true,表示已初始化
} else {
// 已被其他线程初始化,直接用 connRef.getReference()
}
注意点与常见陷阱
-
标记不是“版本号”:它只有 true/false,不支持多状态。需要三态以上请考虑
AtomicStampedReference(带整数 stamp); - ABA 问题仍存在:虽然标记可辅助判断,但若引用从 A→B→A,且标记始终为 false,CAS 仍会成功。若业务敏感,需结合 stamp 使用;
- 标记语义由你定义:true 可代表“已删除”,也可代表“已启用”,取决于你的设计,保持文档清晰;
- 避免 null 引用陷阱:构造时允许 null 引用,但后续 CAS 中 oldRef/newRef 为 null 时要显式写出,不要依赖自动装箱。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











