AtomicMarkableReference 通过一次 CAS 原子操作同时校验引用和布尔标记,需用 get(boolean[]) 获取一致快照,并在 compareAndSet 中传入旧/新引用与旧/新标记四参数,标记语义由业务定义且不可固化。

Java 中 CAS 机制与 AtomicMarkableReference 的配合,核心在于用一次原子操作同时校验“引用值 + 布尔标记”两个维度,从而避免单独更新引用或单独更新状态带来的竞态问题。它不是让 CAS “自动添加标记”,而是由你主动设计标记语义,并在每次 compareAndSet 调用中把标记作为参与比较和更新的必要参数。
必须先获取引用和标记的完整快照
不能只调用 getReference() 或 isMarked() 分开读取——这两者之间可能被其他线程修改,导致“引用是旧的、标记是新的”这种不一致快照。正确做法是使用 get(boolean[]):
- 传入一个长度为 1 的
boolean[]数组,例如boolean[] mark = new boolean[1] - 调用
ref.get(mark),该方法返回当前引用,同时把当前标记写入mark[0] - 后续所有
compareAndSet都基于这个快照中的引用值和标记值构造
CAS 调用要带全四个参数:旧引用、新引用、旧标记、新标记
compareAndSet 不是“设置标记”或“更新引用”的单功能方法,而是一次双条件原子判断+更新:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 只有当当前引用 == 旧引用 且 当前标记 == 旧标记时,才把引用更新为新引用、标记更新为新标记
- 例如想翻转标记(常见于防 ABA):
ref.compareAndSet(current, current, oldMark, !oldMark) - 例如只想改标记不改引用(如标记节点已删除):
ref.compareAndSet(current, current, false, true) - 若只关心引用是否变化,却忽略标记匹配,调用大概率失败——因为标记早已被别的线程改过
标记语义由业务定义,CAS 只负责原子执行
AtomicMarkableReference 不预设标记含义,你需要根据场景赋予它明确逻辑:
立即学习“Java免费学习笔记(深入)”;
- “是否已被逻辑删除”:初始化为
false,删除时尝试从false → true - “是否被修改过”:用占位对象(如
new Object())作引用,仅靠标记从false → true表示首次变更 - “是否发生过中间变更”(防 ABA):每次更新都翻转标记(
!oldMark),哪怕引用没变 - 标记不能静态固定(比如总设为
true),否则失去区分能力,CAS 失去意义
典型错误模式要避开
这些写法看似简洁,实则破坏原子性或陷入死循环:
- ❌
ref.compareAndSet(oldRef, newRef, true, true):硬编码标记,忽略当前真实标记值 - ❌ 在未重读快照的情况下反复调用同一组“旧值”重试:一旦标记被改,永远失败
- ❌ 用
null作占位引用:AtomicMarkableReference允许引用为null,会与“未初始化”混淆,建议用私有常量对象 - ❌ 期望它提供
reset()功能:它没有清空或重置接口,多阶段状态需自行用状态机管理

















