
AtomicStampedReference 通过引入版本戳(stamp)配合对象引用的引用相等性校验来防范 ABA 问题,但其 compareAndSet 成功的前提是:传入的 expectedReference 必须与内部存储的引用完全相同(==),而非值相等;因此必须避免自动装箱/拆箱导致的引用不一致。
atomicstampedreference 通过引入版本戳(stamp)配合对象引用的**引用相等性校验**来防范 aba 问题,但其 `compareandset` 成功的前提是:传入的 `expectedreference` 必须与内部存储的引用**完全相同(==)**,而非值相等;因此必须避免自动装箱/拆箱导致的引用不一致。
AtomicStampedReference 是 Java 并发包中用于解决经典 ABA 问题 的关键工具。它在 AtomicReference 的基础上额外维护一个整型版本戳(stamp),使 compareAndSet 操作同时校验“引用是否未变”和“版本号是否匹配”,从而防止因对象被反复修改回原值(如 A → B → A)而引发的误判。
然而,其核心机制依赖于一个常被忽视的细节:compareAndSet(expectedReference, newReference, expectedStamp, newStamp) 中的 expectedReference == current.reference 是引用比较(==),而非内容比较(.equals())。这意味着:若传入的 expectedReference 是一个新创建或自动装箱产生的对象,即使值相同,引用不同,校验也会失败——这正是许多开发者遇到 compareAndSet 总是返回 false 的根本原因。
以计数器为例,常见错误写法如下:
public int increment() {
int[] stampHolder = new int[1];
int current; // ❌ 基本类型:触发自动拆箱
int next;
do {
current = value.get(stampHolder); // Integer → int,丢失原始引用
next = current + 1;
} while (!value.compareAndSet(current, next, stampHolder[0], stampHolder[0] + 1));
return next;
}问题在于:value.get(stampHolder) 返回的是 Integer 对象,但赋值给 int current 会触发自动拆箱;随后调用 compareAndSet(current, ...) 时,current 又被自动装箱为新的 Integer 实例。由于 Java 的 Integer 缓存机制仅对 -128 ~ 127 范围内数值保证复用同一对象,超出该范围(如 128, 1000)每次装箱都会生成新对象,导致 expectedReference == current.reference 恒为 false,CAS 永远失败。
✅ 正确做法是全程保持引用一致性:
public int increment() {
int[] stampHolder = new int[1];
Integer current; // ✅ 使用包装类型,保留原始引用
int next;
do {
current = value.get(stampHolder); // 直接获取堆中原始 Integer 引用
next = current + 1;
} while (!value.compareAndSet(current, next, stampHolder[0], stampHolder[0] + 1));
return next;
}此时 current 持有 AtomicStampedReference 内部 Pair 所保存的同一个 Integer 实例引用,compareAndSet 中的引用比较才能成功,stamp 的递增也确保了即使值回到 A,版本号已不同,从而真正规避 ABA 风险。
? 关键注意事项:
- 始终使用泛型对应的包装类型(如
Integer、String、自定义不可变对象)作为AtomicStampedReference<v></v>的V,并确保操作中传递的expectedReference是同一对象引用; - 避免在 CAS 循环中对引用类型做无意识的装箱/拆箱;
-
stamp应视为逻辑版本号,推荐使用单调递增(如stamp++)而非随机数,便于调试与语义理解; -
AtomicStampedReference适用于值对象可变性低、需强一致性校验的场景(如带版本的状态机、带时间戳的资源引用),不适用于高频更新且 stamp 易溢出的极端情况。
综上,AtomicStampedReference 并非“自动修复 ABA”,而是提供了一套可组合的原子校验机制;其有效性高度依赖开发者对引用语义与 JVM 装箱规则的精准把握。

















