AtomicStampedReference 通过“值+版本号”原子打包和双条件 CAS 解决 ABA 问题;普通 AtomicReference 仅校验引用值,遇 A→B→A 场景会误判成功,而 AtomicStampedReference 要求值与版本号同时匹配才更新,避免无锁数据结构逻辑错误。

Java 中用 AtomicStampedReference 防 ABA 问题,核心是把“值 + 版本号”打包成一个原子单元,在 CAS 操作时同时校验二者是否匹配,避免只比值导致的误判。
为什么需要 AtomicStampedReference?
普通 AtomicReference 只对引用做 CAS,如果一个对象被修改后又恢复原值(比如 A→B→A),CAS 会误认为没变而成功,这就是 ABA 问题。某些场景下(如栈、队列的无锁实现)这会导致逻辑错误。AtomicStampedReference 通过引入版本戳(stamp),让每次修改都带上递增的标记,即使值回到 A,stamp 已不同,CAS 就会失败。
基本用法:初始化与获取当前值和版本
构造时需传入初始引用和初始 stamp(通常为 0);调用 get() 返回 Pair<V, Integer>,即当前值和当前版本号:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
AtomicStampedReference<String> ref = new AtomicStampedReference<>("A", 0);
int[] stampHolder = new int[1];
String current = ref.get(stampHolder); // 值存入 current,版本号写入 stampHolder[0]
CAS 操作:必须同时提供旧值和旧版本
compareAndSet(V expectedReference, V newReference, int expectedStamp, int newStamp) 是关键方法。只有当当前值等于 expectedReference 且当前版本等于 expectedStamp 时,才更新为新值和新版本:
立即学习“Java免费学习笔记(深入)”;
- 每次修改前,先用
get()获取当前值和 stamp - 计算新值和新 stamp(通常 oldStamp + 1)
- 调用
compareAndSet,传入“旧值、新值、旧 stamp、新 stamp” - 失败则重试(典型自旋逻辑)
注意 stamp 的管理方式
stamp 本身不自动递增,需由使用者控制。常见做法是每次成功 CAS 后手动加 1,或用 AtomicInteger 维护全局版本号。但要注意:
– stamp 溢出(Integer.MAX_VALUE)后会回绕为 Integer.MIN_VALUE,若业务允许重复使用相同 stamp,需自行处理;
– 不建议直接用时间戳或随机数代替 stamp,因为 CAS 要求可预测的、单调的版本变化;
– 多线程并发修改同一 ref 时,stamp 必须与值变更严格对应,不能漏更新或重复使用。

















