AtomicStampedReference
AtomicStampedReference 能解决什么问题?什么时候使用 AtomicStampedReference?
1)AtomicStampedReference 维护带有整数标识的对象引用,可以用原子方式对其进行更新。
2)AtomicStampedReference 能够解决 CAS 的 ABA 问题。
如何使用 AtomicStampedReference?
1)使用 AtomicStampedReference 解决无锁 CAS 过程中的 ABA 问题,特别是涉及资金时。
使用 AtomicStampedReference 有什么风险?
1)高并发场景下,自旋 CAS 长时间失败会导致 CPU 飙升
AtomicStampedReference 核心操作的实现原理?
创建实例
private static class Pair<T> {
/**
* 目标对象引用
*/
final T reference;
/**
* 整形标记
*/
final int stamp;
private Pair(T reference, int stamp) {
this.reference = reference;
this.stamp = stamp;
}
static <T> Pair<T> of(T reference, int stamp) {
return new Pair<>(reference, stamp);
}
}
private volatile Pair<V> pair;
/**
* 创建具有给定对象引用和标识值的新 AtomicStampedReference 实例
*/
public AtomicStampedReference(V initialRef, int initialStamp) {
pair = Pair.of(initialRef, initialStamp);
}
尝试原子更新
/**
* 如果旧引用==expectedReference && 旧整形标记==expectedStamp,
* 则尝试原子更新引用为 newReference,时间标记为 newStamp
*/
public boolean compareAndSet(V expectedReference,
V newReference,
int expectedStamp,
int newStamp) {
final Pair<V> current = pair;
return
expectedReference == current.reference &&
expectedStamp == current.stamp &&
(newReference == current.reference &&
newStamp == current.stamp ||
casPair(current, Pair.of(newReference, newStamp)));
}
读取值
/**
* 读取引用值
*/
public V getReference() {
return pair.reference;
}
/**
* 读取整形标记
*/
public int getStamp() {
return pair.stamp;
}
/**
* 读取引用值,并将整形标记存储到形参数组索引为 0 的位置
*/
public V get(int[] stampHolder) {
final Pair<V> pair = this.pair;
stampHolder[0] = pair.stamp;
return pair.reference;
}
写入值
/**
* 无条件地更新引用值和时间标记
*/
public void set(V newReference, int newStamp) {
final Pair<V> current = pair;
if (newReference != current.reference || newStamp != current.stamp) {
this.pair = Pair.of(newReference, newStamp);
}
}
原子更新值,并发更新时可能失败
/**
* 如果旧引用==expectedReference && 旧整形标记==expectedStamp,
* 则尝试原子更新引用为 newReference,时间标记为 newStamp
*/
public boolean weakCompareAndSet(V expectedReference,
V newReference,
int expectedStamp,
int newStamp) {
return compareAndSet(expectedReference, newReference,
expectedStamp, newStamp);
}
/**
* 如果旧引用==expectedReference && 旧整形标记==expectedStamp,
* 则尝试原子更新引用为 newReference,时间标记为 newStamp
*/
public boolean compareAndSet(V expectedReference,
V newReference,
int expectedStamp,
int newStamp) {
final Pair<V> current = pair;
return
expectedReference == current.reference &&
expectedStamp == current.stamp &&
(newReference == current.reference &&
newStamp == current.stamp ||
casPair(current, Pair.of(newReference, newStamp)));
}
private static final VarHandle PAIR;
static {
try {
final MethodHandles.Lookup l = MethodHandles.lookup();
PAIR = l.findVarHandle(AtomicStampedReference.class, "pair",
Pair.class);
} catch (final ReflectiveOperationException e) {
throw new Error(e);
}
}
private boolean casPair(Pair<V> cmp, Pair<V> val) {
return AtomicStampedReference.PAIR.compareAndSet(this, cmp, val);
}