JDK 8 AtomicStampedReference 源码详解(详细注释版)
1. 类定义和基本属性
public class AtomicStampedReference<V> implements java.io.Serializable {
// 序列化版本号
private static final long serialVersionUID = -5499324414565895908L;
/**
* Pair内部类,用于封装引用和时间戳
* 这是解决ABA问题的关键设计
* 通过引入版本号(时间戳)来区分相同值的不同状态
*/
private static class Pair<T> {
final T reference; // 引用值
final int stamp; // 时间戳/版本号
/**
* 私有构造方法,创建Pair实例
* @param reference 引用值
* @param stamp 时间戳
*/
private Pair(T reference, int stamp) {
this.reference = reference;
this.stamp = stamp;
}
/**
* 静态工厂方法,创建Pair实例
* @param reference 引用值
* @param stamp 时间戳
* @return 新的Pair实例
*/
static <T> Pair<T> of(T reference, int stamp) {
return new Pair<T>(reference, stamp);
}
}
/**
* Unsafe类实例,提供底层的原子操作
* 通过Unsafe可以直接操作内存地址,实现CAS等原子操作
*/
private static final sun.misc.Unsafe unsafe = getUnsafe();
/**
* pair字段在对象中的偏移量
* 通过这个偏移量可以使用Unsafe直接操作pair字段的内存地址
* 这是实现原子操作的关键
*/
private static final long pairOffset;
/**
* 静态初始化块,获取pair字段的偏移量
* 在类加载时执行,确保偏移量的正确性
*/
static {
try {
// 获取pair字段的偏移量
pairOffset = unsafe.objectFieldOffset
(AtomicStampedReference.class.getDeclaredField("pair"));
} catch (Exception ex) {
throw new Error(ex);
}
}
/**
* 获取Unsafe实例的方法
* 由于Unsafe类的特殊性,需要通过反射获取实例
* @return Unsafe实例
*/
private static sun.misc.Unsafe getUnsafe() {
try {
return sun.misc.Unsafe.getUnsafe();
} catch (SecurityException se) {
try {
return java.security.AccessController.doPrivileged
(new java.security.PrivilegedExceptionAction<sun.misc.Unsafe>() {
public sun.misc.Unsafe run() throws Exception {
Class<sun.misc.Unsafe> k = sun.misc.Unsafe.class;
for (java.lang.reflect.Field f : k.getDeclaredFields()) {
f.setAccessible(true);
Object x = f.get(null);
if (k.isInstance(x))
return k.cast(x);
}
throw new NoSuchFieldError("the Unsafe");
}});
} catch (java.security.PrivilegedActionException e) {
throw new RuntimeException("Could not initialize intrinsics",
e.getCause());
}
}
}
/**
* 实际存储的Pair对象
* 使用volatile修饰确保内存可见性
* 所有原子操作都是针对这个字段进行的
*
* 设计巧妙之处:
* - 将引用和时间戳封装在一个对象中
* - 通过CAS操作整个Pair对象来保证原子性
* - 避免了分别操作引用和时间戳可能产生的不一致性
*/
private volatile Pair<V> pair;
/**
* 默认构造方法
* 创建一个初始引用为null,时间戳为0的AtomicStampedReference
*
* 初始化过程:
* 1. 创建Pair对象,引用为null,时间戳为0
* 2. 设置pair字段
* 3. volatile语义确保对其他线程的可见性
*/
public AtomicStampedReference() {
pair = Pair.of(null, 0);
}
/**
* 指定初始引用和时间戳的构造方法
* @param initialRef 初始引用值
* @param initialStamp 初始时间戳
*
* 初始化过程:
* 1. 创建Pair对象,包含初始引用和时间戳
* 2. 设置pair字段
* 3. volatile语义确保对其他线程的可见性
*/
public AtomicStampedReference(V initialRef, int initialStamp) {
pair = Pair.of(initialRef, initialStamp);
}
/**
* 获取当前引用值
* 由于pair字段是volatile的,这个方法保证返回最新的引用值
*
* 时间复杂度:O(1)
* 线程安全性:完全线程安全
*
* @return 当前引用值
*/
public V getReference() {
return pair.reference;
}
/**
* 获取当前时间戳
* 由于pair字段是volatile的,这个方法保证返回最新的时间戳
*
* 时间复杂度:O(1)
* 线程安全性:完全线程安全
*
* @return 当前时间戳
*/
public int getStamp() {
return pair.stamp;
}
/**
* 同时获取引用值和时间戳
* 这个方法保证返回的引用值和时间戳是一致的
*
* 操作过程:
* 1. 原子地读取当前的Pair对象
* 2. 将引用值和时间戳分别存储到指定数组中
* 3. 保证引用值和时间戳的一致性
*
* 时间复杂度:O(1)
* 线程安全性:完全线程安全
*
* @param stampHolder 用于存储时间戳的数组
* @return 当前引用值
* @throws NullPointerException 如果stampHolder为null
*/
public V get(int[] stampHolder) {
Pair<V> pair = this.pair;
stampHolder[0] = pair.stamp;
return pair.reference;
}
2. 核心原子操作方法(详细注释)
/**
* 原子地比较并设置引用值和时间戳
* 只有当当前引用值和时间戳都等于期望值时,才设置为新值
*
* 操作过程:
* 1. 获取当前的Pair对象
* 2. 比较当前引用值、时间戳与期望值
* 3. 如果都相等,创建新的Pair对象并原子性地更新
* 4. 返回比较结果
*
* ABA问题解决方案:
* - 通过时间戳区分相同值的不同状态
* - 即使引用值从A变为B再变为A,时间戳也会不同
* - 保证了状态变化的唯一性
*
* 时间复杂度:O(1) 平均情况,O(∞) 最坏情况(高竞争)
* 线程安全性:完全原子性
*
* @param expectedReference 期望的引用值
* @param newReference 新的引用值
* @param expectedStamp 期望的时间戳
* @param newStamp 新的时间戳
* @return 如果设置成功返回true,否则返回false
*/
public boolean compareAndSet(V expectedReference,
V newReference,
int expectedStamp,
int newStamp) {
Pair<V> current = pair;
return
expectedReference == current.reference &&
expectedStamp == current.stamp &&
((newReference == current.reference &&
newStamp == current.stamp) ||
casPair(current, Pair.of(newReference, newStamp)));
}
/**
* 弱原子地比较并设置引用值和时间戳
* 与compareAndSet类似,但在某些平台上可能不提供完全的内存排序保证
*
* 使用场景:
* - 对内存排序要求不严格的场景
* - 性能要求极高的场景
*
* @param expectedReference 期望的引用值
* @param newReference 新的引用值
* @param expectedStamp 期望的时间戳
* @param newStamp 新的时间戳
* @return 如果设置成功返回true,否则返回false
*/
public boolean weakCompareAndSet(V expectedReference,
V newReference,
int expectedStamp,
int newStamp) {
return compareAndSet(expectedReference, newReference,
expectedStamp, newStamp);
}
/**
* 原子地设置引用值和时间戳
* 这个操作不是原子的,只是简单地设置新值
*
* 注意事项:
* - 这个方法不保证原子性
* - 如果需要原子性设置,应该使用compareAndSet方法
* - volatile语义确保新值对其他线程可见
*
* @param newReference 新的引用值
* @param newStamp 新的时间戳
*/
public void set(V newReference, int newStamp) {
Pair<V> current = pair;
if (newReference != current.reference || newStamp != current.stamp)
this.pair = Pair.of(newReference, newStamp);
}
/**
* 原子地设置引用值并返回旧值和旧时间戳
* 这是一个原子操作,保证读取和设置的原子性
*
* 操作过程:
* 1. 原子地设置新引用值和时间戳
* 2. 返回旧的引用值和时间戳
*
* 时间复杂度:O(1) 平均情况,O(∞) 最坏情况(高竞争)
* 线程安全性:完全原子性
*
* @param newReference 新的引用值
* @param newStamp 新的时间戳
* @param stampHolder 用于存储旧时间戳的数组
* @return 旧的引用值
*/
public V getAndSet(V newReference, int newStamp, int[] stampHolder) {
Pair<V> current = pair;
stampHolder[0] = current.stamp;
if (newReference != current.reference || newStamp != current.stamp)
this.pair = Pair.of(newReference, newStamp);
return current.reference;
}
/**
* 原子地尝试设置引用值
* 只有当当前引用值等于期望值时,才设置为新值
*
* 操作过程:
* 1. 获取当前的Pair对象
* 2. 比较当前引用值与期望值
* 3. 如果相等,创建新的Pair对象并原子性地更新
* 4. 返回比较结果
*
* 时间复杂度:O(1) 平均情况,O(∞) 最坏情况(高竞争)
* 线程安全性:完全原子性
*
* @param expectedReference 期望的引用值
* @param newReference 新的引用值
* @param expectedStamp 期望的时间戳
* @param newStamp 新的时间戳
* @return 如果设置成功返回true,否则返回false
*/
public boolean attemptStamp(V expectedReference, int newStamp) {
Pair<V> current = pair;
return
expectedReference == current.reference &&
(newStamp == current.stamp ||
casPair(current, Pair.of(expectedReference, newStamp)));
}
/**
* CAS操作更新pair字段
* @param cmp 预期的当前值
* @param val 新值
* @return 如果更新成功返回true,否则返回false
*/
private boolean casPair(Pair<V> cmp, Pair<V> val) {
return unsafe.compareAndSwapObject(this, pairOffset, cmp, val);
}
3. ABA问题分析和解决方案
ABA问题详解:
/**
* ABA问题分析:
*
* 什么是ABA问题?
* ABA问题是指在并发环境下,一个变量的值从A变为B,再从B变为A,
* 在这个过程中,其他线程可能基于错误的假设执行操作。
*
* 经典例子:
* 线程1准备更新共享变量:
* 1. 读取变量值:A
* 2. 执行一些耗时操作...
*
* 线程2在期间执行:
* 1. 将变量从A更新为B
* 2. 将变量从B更新为A
*
* 线程1继续执行:
* 1. 发现变量值仍然是A(但实际上中间状态发生了变化)
* 2. 基于错误的假设执行更新操作
* 3. 可能导致不一致的状态
*
* ABA问题的危害:
* - 数据不一致
* - 状态错误
* - 逻辑错误
* - 难以调试和重现
*
* AtomicStampedReference如何解决ABA问题:
*
* 1. 引入时间戳机制:
* - 每次更新引用值时,同时更新时间戳
* - 时间戳单调递增,不会重复
* - 即使引用值相同,时间戳也不同
*
* 2. 原子性保证:
* - 将引用值和时间戳封装在Pair对象中
* - 通过CAS操作整个Pair对象
* - 保证引用值和时间戳的一致性
*
* 3. 版本控制:
* - 每次更新都增加版本号
* - 通过版本号区分相同值的不同状态
* - 避免基于过时状态的错误操作
*
* 使用示例:
*
* // 不使用AtomicStampedReference可能出现ABA问题
* class WithoutStampExample {
* private AtomicReference<Node> head = new AtomicReference<>();
*
* public void problematicOperation() {
* Node oldHead = head.get(); // 获取到head=A
*
* // 在此期间其他线程执行:A -> B -> A
* // head值仍然是A,但中间状态发生了变化
*
* // 线程继续执行,基于错误的假设
* head.compareAndSet(oldHead, newHead); // 可能导致问题
* }
* }
*
* // 使用AtomicStampedReference解决ABA问题
* class WithStampExample {
* private AtomicStampedReference<Node> head =
* new AtomicStampedReference<>(null, 0);
*
* public void safeOperation() {
* int[] stampHolder = new int[1];
* Node oldHead = head.get(stampHolder); // 获取引用值和时间戳
* int oldStamp = stampHolder[0];
*
* // 在此期间其他线程执行:A(stamp=1) -> B(stamp=2) -> A(stamp=3)
* // 虽然引用值相同,但时间戳不同
*
* // 线程继续执行,时间戳检查会失败
* boolean success = head.compareAndSet(oldHead, newHead,
* oldStamp, oldStamp + 1);
* if (!success) {
* // 处理ABA问题,重新获取最新状态
* System.out.println("ABA problem detected, retry operation");
* }
* }
* }
*
* 实际应用场景:
*
* 1. 无锁栈实现:
* class LockFreeStack<T> {
* private AtomicStampedReference<Node<T>> top =
* new AtomicStampedReference<>(null, 0);
*
* private static class Node<T> {
* final T data;
* Node<T> next;
*
* Node(T data, Node<T> next) {
* this.data = data;
* this.next = next;
* }
* }
*
* public void push(T item) {
* Node<T> newHead;
* Node<T> currentHead;
* int[] stampHolder = new int[1];
* int currentStamp;
*
* do {
* currentHead = top.get(stampHolder);
* currentStamp = stampHolder[0];
* newHead = new Node<>(item, currentHead);
* } while (!top.compareAndSet(currentHead, newHead,
* currentStamp, currentStamp + 1));
* }
*
* public T pop() {
* Node<T> currentHead;
* Node<T> newHead;
* int[] stampHolder = new int[1];
* int currentStamp;
*
* do {
* currentHead = top.get(stampHolder);
* currentStamp = stampHolder[0];
* if (currentHead == null)
* return null;
* newHead = currentHead.next;
* } while (!top.compareAndSet(currentHead, newHead,
* currentStamp, currentStamp + 1));
*
* return currentHead.data;
* }
* }
*
* 2. 无锁队列实现:
* class LockFreeQueue<T> {
* private AtomicStampedReference<Node<T>> head;
* private AtomicStampedReference<Node<T>> tail;
*
* private static class Node<T> {
* final T data;
* volatile Node<T> next;
*
* Node(T data) {
* this.data = data;
* this.next = null;
* }
* }
*
* public LockFreeQueue() {
* Node<T> dummy = new Node<>(null);
* head = new AtomicStampedReference<>(dummy, 0);
* tail = new AtomicStampedReference<>(dummy, 0);
* }
*
* public void enqueue(T item) {
* Node<T> newNode = new Node<>(item);
* int[] stampHolder = new int[1];
*
* while (true) {
* Node<T> currentTail = tail.get(stampHolder);
* int currentStamp = stampHolder[0];
*
* if (currentTail.next == null) {
* if (currentTail.next == null) {
* if (tail.compareAndSet(currentTail, newNode,
* currentStamp, currentStamp + 1)) {
* break;
* }
* }
* } else {
* // 帮助其他线程完成尾部更新
* tail.compareAndSet(currentTail, currentTail.next,
* currentStamp, currentStamp + 1);
* }
* }
* }
*
* public T dequeue() {
* int[] stampHolder = new int[1];
*
* while (true) {
* Node<T> currentHead = head.get(stampHolder);
* int headStamp = stampHolder[0];
* Node<T> currentTail = tail.get(stampHolder);
* int tailStamp = stampHolder[0];
* Node<T> next = currentHead.next;
*
* if (currentHead == head.get(stampHolder) &&
* headStamp == stampHolder[0]) {
* if (currentHead == currentTail) {
* if (next == null)
* return null;
* tail.compareAndSet(currentTail, next,
* tailStamp, tailStamp + 1);
* } else {
* T data = next.data;
* if (head.compareAndSet(currentHead, next,
* headStamp, headStamp + 1)) {
* return data;
* }
* }
* }
* }
* }
* }
*
* 3. 内存管理中的ABA问题:
* class MemoryPool {
* private AtomicStampedReference<Block> freeList =
* new AtomicStampedReference<>(null, 0);
*
* private static class Block {
* byte[] data = new byte[1024];
* Block next;
* }
*
* public Block allocate() {
* int[] stampHolder = new int[1];
* Block currentHead;
* int currentStamp;
*
* do {
* currentHead = freeList.get(stampHolder);
* currentStamp = stampHolder[0];
* if (currentHead == null) {
* return new Block(); // 分配新块
* }
* } while (!freeList.compareAndSet(currentHead, currentHead.next,
* currentStamp, currentStamp + 1));
*
* return currentHead;
* }
*
* public void deallocate(Block block) {
* int[] stampHolder = new int[1];
* Block currentHead;
* int currentStamp;
*
* do {
* currentHead = freeList.get(stampHolder);
* currentStamp = stampHolder[0];
* block.next = currentHead;
* } while (!freeList.compareAndSet(currentHead, block,
* currentStamp, currentStamp + 1));
* }
* }
*/
4. AtomicStampedReference 的特点分析
核心设计理念:
/**
* AtomicStampedReference的核心设计思想:
*
* 1. 版本控制机制:
* - 引入时间戳/版本号概念
* - 通过版本号区分相同值的不同状态
* - 解决经典的ABA问题
*
* 2. Pair封装设计:
* - 将引用值和时间戳封装在Pair对象中
* - 通过CAS操作整个Pair对象
* - 保证引用值和时间戳的一致性
*
* 3. 无锁编程:
* - 使用CAS操作实现原子性
* - 避免传统锁的开销和阻塞
* - 提供乐观锁机制
*
* 4. volatile语义:
* - pair字段使用volatile修饰
* - 保证内存可见性
* - 确保读操作获取最新值
*
* 5. Unsafe支持:
* - 使用sun.misc.Unsafe类提供底层原子操作
* - 直接操作内存地址,性能优异
* - 绕过JVM的常规访问控制
*
* 6. 偏移量机制:
* - 通过字段偏移量直接访问内存
* - 避免反射开销
* - 提供精确的内存操作
*
* 7. 自旋重试:
* - CAS失败时自动重试
* - 保证操作的最终成功
* - 适用于竞争不激烈的场景
*
* 8. 线程安全:
* - 所有操作都是线程安全的
* - 适用于高并发环境
* - 无死锁风险
*
* 适用场景:
* - 需要解决ABA问题的场景
* - 无锁数据结构实现
* - 需要版本控制的并发场景
* - 内存池管理
* - 需要精确状态跟踪的场景
*/
性能特征分析:
/**
* AtomicStampedReference的性能特征:
*
* 时间复杂度:
* - getReference(): O(1) - 直接读取volatile字段
* - getStamp(): O(1) - 直接读取volatile字段
* - get(): O(1) - 直接读取volatile字段
* - compareAndSet(): O(1) 平均,O(∞) 最坏
* - set(): O(1) - 直接写入volatile字段
* - getAndSet(): O(1) 平均,O(∞) 最坏
*
* 空间复杂度:
* - O(1) - 只需要存储一个Pair对象和偏移量
* - Pair对象包含引用和时间戳
* - 每个实例固定开销较小
*
* 并发特性:
* - 完全线程安全
* - 无锁设计,避免线程阻塞
* - 乐观锁机制,适用于低竞争场景
* - 高竞争场景下可能出现自旋开销
*
* 与AtomicReference对比:
* - 功能增强:解决ABA问题
* - 性能:AtomicStampedReference < AtomicReference
* - 内存使用:AtomicStampedReference > AtomicReference
* - 适用性:需要版本控制时选择AtomicStampedReference
*
* CAS操作特点:
* - 乐观锁:假设没有冲突,冲突时重试
* - 非阻塞:不会阻塞其他线程
* - 解决ABA:通过时间戳区分相同值的不同状态
* - 自旋开销:高竞争时CPU使用率可能较高
*
* 内存使用:
* - 每个实例固定开销很小
* - volatile字段保证可见性
* - Pair对象包含引用和时间戳
* - 及时GC,避免内存泄漏
*
* 适用性:
* - 解决ABA问题:性能优异
* - 无锁数据结构:性能优异
* - 版本控制:性能优异
* - 简单原子操作:可能不如AtomicReference
*/
5. 使用示例和最佳实践
/**
* 使用示例:
*
* // 基本使用
* AtomicStampedReference<String> ref = new AtomicStampedReference<>("initial", 0);
*
* // 获取引用值和时间戳
* int[] stampHolder = new int[1];
* String reference = ref.get(stampHolder);
* int stamp = stampHolder[0];
* System.out.println("Reference: " + reference + ", Stamp: " + stamp);
*
* // 原子地比较并设置
* boolean success = ref.compareAndSet("initial", "updated", 0, 1);
* if (success) {
* System.out.println("Update successful");
* } else {
* System.out.println("Update failed");
* }
*
* // 获取单独的引用值和时间戳
* String currentRef = ref.getReference();
* int currentStamp = ref.getStamp();
*
* // 原子地设置新值
* ref.set("new value", 2);
*
* // 原子地设置引用值并返回旧值
* int[] oldStampHolder = new int[1];
* String oldReference = ref.getAndSet("another value", 3, oldStampHolder);
* int oldStamp = oldStampHolder[0];
* System.out.println("Old reference: " + oldReference + ", Old stamp: " + oldStamp);
*
* // 尝试更新时间戳
* boolean stampSuccess = ref.attemptStamp("another value", 4);
* if (stampSuccess) {
* System.out.println("Stamp update successful");
* } else {
* System.out.println("Stamp update failed");
* }
*
* // 无锁栈实现示例
* class LockFreeStack<T> {
* private AtomicStampedReference<Node<T>> top =
* new AtomicStampedReference<>(null, 0);
*
* private static class Node<T> {
* final T data;
* Node<T> next;
*
* Node(T data, Node<T> next) {
* this.data = data;
* this.next = next;
* }
* }
*
* public void push(T item) {
* Node<T> newHead;
* Node<T> currentHead;
* int[] stampHolder = new int[1];
* int currentStamp;
*
* do {
* currentHead = top.get(stampHolder);
* currentStamp = stampHolder[0];
* newHead = new Node<>(item, currentHead);
* } while (!top.compareAndSet(currentHead, newHead,
* currentStamp, currentStamp + 1));
* }
*
* public T pop() {
* Node<T> currentHead;
* Node<T> newHead;
* int[] stampHolder = new int[1];
* int currentStamp;
*
* do {
* currentHead = top.get(stampHolder);
* currentStamp = stampHolder[0];
* if (currentHead == null)
* return null;
* newHead = currentHead.next;
* } while (!top.compareAndSet(currentHead, newHead,
* currentStamp, currentStamp + 1));
*
* return currentHead.data;
* }
* }
*
* // 内存池管理示例
* class MemoryPool {
* private AtomicStampedReference<Block> freeList =
* new AtomicStampedReference<>(null, 0);
*
* private static class Block {
* byte[] data = new byte[1024];
* Block next;
* }
*
* public Block allocate() {
* int[] stampHolder = new int[1];
* Block currentHead;
* int currentStamp;
*
* do {
* currentHead = freeList.get(stampHolder);
* currentStamp = stampHolder[0];
* if (currentHead == null) {
* return new Block(); // 分配新块
* }
* } while (!freeList.compareAndSet(currentHead, currentHead.next,
* currentStamp, currentStamp + 1));
*
* return currentHead;
* }
*
* public void deallocate(Block block) {
* int[] stampHolder = new int[1];
* Block currentHead;
* int currentStamp;
*
* do {
* currentHead = freeList.get(stampHolder);
* currentStamp = stampHolder[0];
* block.next = currentHead;
* } while (!freeList.compareAndSet(currentHead, block,
* currentStamp, currentStamp + 1));
* }
* }
*
* // 版本控制示例
* class VersionedObject<T> {
* private AtomicStampedReference<T> versionedRef;
*
* public VersionedObject(T initialValue) {
* versionedRef = new AtomicStampedReference<>(initialValue, 0);
* }
*
* public boolean update(T expected, T newValue) {
* int[] stampHolder = new int[1];
* T current = versionedRef.get(stampHolder);
* int currentStamp = stampHolder[0];
*
* if (current != expected) {
* return false; // 值不匹配
* }
*
* return versionedRef.compareAndSet(expected, newValue,
* currentStamp, currentStamp + 1);
* }
*
* public T get(int[] stampHolder) {
* return versionedRef.get(stampHolder);
* }
*
* public T getReference() {
* return versionedRef.getReference();
* }
*
* public int getStamp() {
* return versionedRef.getStamp();
* }
* }
*
* 最佳实践:
*
* 1. 正确使用compareAndSet:
* AtomicStampedReference<String> ref = new AtomicStampedReference<>("value", 0);
*
* // 正确使用:检查返回值
* public boolean tryUpdate(String expectedRef, String newRef,
* int expectedStamp, int newStamp) {
* return ref.compareAndSet(expectedRef, newRef, expectedStamp, newStamp);
* }
*
* // 错误使用:忽略返回值
* // ref.compareAndSet("old", "new", 0, 1); // 没有检查返回值
*
* 2. 合理使用时间戳:
* AtomicStampedReference<String> ref = new AtomicStampedReference<>("value", 0);
*
* // 时间戳应该单调递增
* public void updateValue(String newValue) {
* int[] stampHolder = new int[1];
* String currentRef = ref.get(stampHolder);
* int currentStamp = stampHolder[0];
* ref.compareAndSet(currentRef, newValue, currentStamp, currentStamp + 1);
* }
*
* // 避免时间戳回绕
* public void safeUpdate(String newValue) {
* int[] stampHolder = new int[1];
* String currentRef = ref.get(stampHolder);
* int currentStamp = stampHolder[0];
* int newStamp = (currentStamp == Integer.MAX_VALUE) ? 0 : currentStamp + 1;
* ref.compareAndSet(currentRef, newValue, currentStamp, newStamp);
* }
*
* 3. 处理ABA问题:
* AtomicStampedReference<Node> ref = new AtomicStampedReference<>(null, 0);
*
* // 正确处理ABA问题
* public boolean safeUpdate(Node expected, Node newValue) {
* int[] stampHolder = new int[1];
* Node current = ref.get(stampHolder);
* int currentStamp = stampHolder[0];
*
* // 检查引用值和时间戳
* if (current != expected) {
* System.out.println("Reference changed, ABA problem detected");
* return false;
* }
*
* return ref.compareAndSet(expected, newValue, currentStamp, currentStamp + 1);
* }
*
* 4. 数组参数的正确使用:
* AtomicStampedReference<String> ref = new AtomicStampedReference<>("value", 0);
*
* // 正确使用数组参数
* int[] stampHolder = new int[1];
* String reference = ref.get(stampHolder);
* int stamp = stampHolder[0];
*
* // 错误使用:数组长度不足
* // int[] shortArray = new int[0];
* // String ref = ref.get(shortArray); // ArrayIndexOutOfBoundsException
*
* 5. 异常处理:
* AtomicStampedReference<String> ref = new AtomicStampedReference<>("value", 0);
*
* public void safeUpdate(String expectedRef, String newRef,
* int expectedStamp, int newStamp) {
* try {
* boolean success = ref.compareAndSet(expectedRef, newRef, expectedStamp, newStamp);
* if (success) {
* System.out.println("Update successful");
* } else {
* System.out.println("Update failed");
* }
* } catch (Exception e) {
* System.err.println("Update failed: " + e.getMessage());
* // 记录日志或采取其他措施
* }
* }
*
* 6. 性能优化:
* // 在高并发场景下监控性能
* AtomicStampedReference<String> ref = new AtomicStampedReference<>("value", 0);
*
* // 使用局部变量减少volatile访问
* public void optimizedAccess() {
* int[] stampHolder = new int[1];
* String localRef = ref.get(stampHolder);
* int localStamp = stampHolder[0];
*
* if (localRef != null && localStamp > 0) {
* // 执行相关逻辑
* }
* }
*
* // 避免不必要的原子操作
* public void conditionalUpdate(String newValue) {
* int[] stampHolder = new int[1];
* String currentRef = ref.get(stampHolder);
* if (currentRef == null) { // 先检查
* int currentStamp = stampHolder[0];
* ref.compareAndSet(null, newValue, currentStamp, currentStamp + 1);
* }
* }
*
* 7. 监控和调试:
* AtomicStampedReference<String> ref = new AtomicStampedReference<>("value", 0);
*
* // 定期检查状态
* public void logStatus() {
* System.out.println("Reference: " + ref.getReference());
* System.out.println("Stamp: " + ref.getStamp());
* }
*
* // 性能监控
* public void monitorPerformance() {
* long startTime = System.nanoTime();
* // 执行一些操作
* for (int i = 0; i < 1000000; i++) {
* int[] stampHolder = new int[1];
* String currentRef = ref.get(stampHolder);
* int currentStamp = stampHolder[0];
* ref.compareAndSet(currentRef, "new_value_" + i, currentStamp, currentStamp + 1);
* }
* long endTime = System.nanoTime();
* System.out.println("Time taken: " + (endTime - startTime) + " ns");
* }
*
* 8. 内存管理:
* // 注意避免内存泄漏
* AtomicStampedReference<LargeObject> ref =
* new AtomicStampedReference<>(new LargeObject(), 0);
*
* public void cleanup() {
* // 适当时清理大对象
* ref.set(null, ref.getStamp() + 1);
* }
*
* 9. 线程安全的初始化:
* class ThreadSafeInitializer<T> {
* private final AtomicStampedReference<T> ref =
* new AtomicStampedReference<>(null, 0);
*
* public T getInstance(Supplier<T> supplier) {
* T instance = ref.getReference();
* if (instance == null) {
* instance = supplier.get();
* int[] stampHolder = new int[1];
* T current = ref.get(stampHolder);
* if (current == null) {
* int currentStamp = stampHolder[0];
* ref.compareAndSet(null, instance, currentStamp, currentStamp + 1);
* }
* instance = ref.getReference(); // 可能是其他线程创建的实例
* }
* return instance;
* }
* }
*
* 10. 批量操作优化:
* // 当需要多个相关更新时,考虑原子性
* class BatchUpdater {
* private final AtomicStampedReference<Data> ref;
*
* public void batchUpdate(List<UpdateOperation> operations) {
* int[] stampHolder = new int[1];
* Data currentData;
* int currentStamp;
*
* do {
* currentData = ref.get(stampHolder);
* currentStamp = stampHolder[0];
* Data newData = applyOperations(currentData, operations);
* } while (!ref.compareAndSet(currentData, newData,
* currentStamp, currentStamp + 1));
* }
*
* private Data applyOperations(Data data, List<UpdateOperation> operations) {
* Data result = data.clone(); // 克隆数据避免副作用
* for (UpdateOperation op : operations) {
* op.apply(result);
* }
* return result;
* }
* }
*/
6. 与其他原子类的比较
/**
* AtomicStampedReference vs AtomicReference vs AtomicMarkableReference:
*
* AtomicStampedReference:
* - 用于解决ABA问题
* - 包含引用值和整数时间戳
* - 支持版本控制
* - 适用于需要精确状态跟踪的场景
* - 内存使用较大(引用+整数)
* - 功能最丰富
*
* AtomicReference:
* - 简单的原子引用操作
* - 只包含引用值
* - 不解决ABA问题
* - 适用于简单的原子操作
* - 内存使用最小
* - 性能最好
*
* AtomicMarkableReference:
* - 包含引用值和布尔标记
* - 适用于简单的标记场景
* - 不解决ABA问题
* - 内存使用适中(引用+布尔值)
* - 功能适中
*
* 性能对比:
* - 基本操作:AtomicReference > AtomicMarkableReference > AtomicStampedReference
* - 内存使用:AtomicReference < AtomicMarkableReference < AtomicStampedReference
* - 功能丰富度:AtomicStampedReference > AtomicMarkableReference > AtomicReference
*
* 选择建议:
* - 简单原子操作:AtomicReference
* - 需要布尔标记:AtomicMarkableReference
* - 需要解决ABA问题:AtomicStampedReference
* - 需要版本控制:AtomicStampedReference
* - 高性能要求:AtomicReference
*
* 使用场景:
* - AtomicStampedReference:无锁数据结构、内存池、版本控制
* - AtomicReference:简单的原子操作、缓存引用
* - AtomicMarkableReference:标记状态、简单标志位
*/
7. 总结
AtomicStampedReference 的核心特性:
-
ABA问题解决方案:
- 通过时间戳/版本号区分相同值的不同状态
- 保证状态变化的唯一性
- 避免基于过时状态的错误操作
-
Pair封装设计:
- 将引用值和时间戳封装在Pair对象中
- 通过CAS操作整个Pair对象
- 保证引用值和时间戳的一致性
-
无锁原子操作:
- 使用CAS实现原子性
- 避免传统锁的开销
- 提供乐观锁机制
-
内存可见性:
- pair字段使用volatile修饰
- 保证多线程间的内存可见性
- 确保读操作获取最新值
-
丰富的原子操作:
- 基本的get/set操作
- 比较并设置操作
- 原子地设置并返回旧值
- 尝试更新时间戳操作
-
线程安全:
- 所有操作都是线程安全的
- 适用于高并发环境
- 无死锁风险
适用场景:
- 需要解决ABA问题的场景
- 无锁数据结构实现
- 需要版本控制的并发场景
- 内存池管理
- 需要精确状态跟踪的场景
- 高并发环境下的原子操作
注意事项:
- CAS操作可能出现自旋开销
- 高竞争场景下性能可能下降
- 需要正确处理CAS的返回值
- 注意时间戳的合理使用
- 数组参数必须正确初始化
- 避免不必要的原子操作
性能优化建议:
- 根据需求选择合适的原子类
- 合理使用compareAndSet避免不必要的操作
- 在高竞争场景下考虑减少竞争
- 监控原子操作的性能表现
- 避免频繁的原子操作
- 正确处理CAS的返回值
- 使用局部变量减少volatile访问
- 合理管理时间戳的增长
- 避免内存泄漏
- 定期清理不需要的对象

&spm=1001.2101.3001.5002&articleId=149646278&d=1&t=3&u=5a37f729c44f408498bf9dca0de1eb3f)
1116

被折叠的 条评论
为什么被折叠?



