/**
* AtomicStampedReference 维护带有整数“标志”的对象引用,可以用原子方式对其进行更新。
*
* 实现注意事项。通过创建表示“已装箱”的 [reference, integer] 对的内部对象,此实现维持带标志的引用。
* @param <V> 此引用引用的对象的类型
*/
public class AtomicStampedReference<V> {
private static class Pair<T> {
final T reference;
final int stamp;
/**
*
* @param reference 引用
* @param stamp 标志
*/
private Pair(T reference, int stamp) {
this.reference = reference;
this.stamp = stamp;
}
/**
* 静态工厂
* @param reference 引用
* @param stamp 标志
* @param <T> 此引用引用的对象的类型
* @return
*/
static <T> Pair<T> of(T reference, int stamp) {
return new Pair<T>(reference, stamp);
}
}
private volatile Pair<V> pair;
/**
* 创建具有给定初始值的新 AtomicStampedReference。
* @param initialRef 初始引用
* @param initialStamp 初始标志
*/
public AtomicStampedReference(V initialRef, int initialStamp) {
pair = Pair.of(initialRef, initialStamp);
}
/**
* 返回该引用的当前值。
* @return 该引用的当前值
*/
public V getReference() {
return pair.reference;
}
/**
* 返回该标志的当前值。
* @return 该标志的当前值
*/
public int getStamp() {
return pair.stamp;
}
/**
* 返回该引用和该标志的当前值。典型的用法为 int[1] holder; ref = v.get(holder); 。
* @param stampHolder 大小至少为 1 的数组。返回时,stampholder[0] 将保存该标志的值。
* @return 该引用的当前值
*/
public V get(int[] stampHolder) {
Pair<V> pair = this.pair;
stampHolder[0] = pair.stamp;
return pair.reference;
}
/**
* 如果当前引用 == 预期引用,并且当前标志等于预期标志,则以原子方式将该引用和该标志的值设置为给定的更新值。
* 可能意外失败并且不提供排序保证,所以只有在很少的情况下才对 compareAndSet 进行适当的选择。
* @param expectedReference 该引用的预期值
* @param newReference 该引用的新值
* @param expectedStamp 该标志的预期值
* @param newStamp 该标志的新值
* @return 如果成功,则返回 true
*/
public boolean weakCompareAndSet(V expectedReference,
V newReference,
int expectedStamp,
int newStamp) {
return compareAndSet(expectedReference, newReference,
expectedStamp, newStamp);
}
/**
* 如果当前引用 == 预期引用,并且当前标志等于预期标志,则以原子方式将该引用和该标志的值设置为给定的更新值。
* @param expectedReference 该引用的预期值
* @param newReference 该引用的新值
* @param expectedStamp 该标志的预期值
* @param newStamp 该标志的新值
* @return 如果成功,则返回 true
*/
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)));
}
/**
* 无条件地同时设置该引用和标志的值。
* @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);
}
/**
* 如果当前引用 == 预期引用,则以原子方式将该标志的值设置为给定的更新值。此操作的任何给定调用都可能会意外失败(返回 false),
* 但是在当前值保持预期值而且没有其他线程也在尝试设置该值时,重复调用将最终获得成功。
* @param expectedReference 该引用的预期值
* @param newStamp 该标志的新值
* @return 如果成功,则返回 true
*/
public boolean attemptStamp(V expectedReference, int newStamp) {
Pair<V> current = pair;
return
expectedReference == current.reference &&
(newStamp == current.stamp ||
casPair(current, Pair.of(expectedReference, newStamp)));
}
// 不安全机制
private static final sun.misc.Unsafe UNSAFE = sun.misc.Unsafe.getUnsafe();
private static final long pairOffset =
objectFieldOffset(UNSAFE, "pair", AtomicStampedReference.class);
/**
* pair比对
* @param cmp
* @param val
* @return
*/
private boolean casPair(Pair<V> cmp, Pair<V> val) {
return UNSAFE.compareAndSwapObject(this, pairOffset, cmp, val);
}
/**
* 获取偏移量
* @param UNSAFE
* @param field 字段名
* @param klazz 类型
* @return
*/
static long objectFieldOffset(sun.misc.Unsafe UNSAFE,
String field, Class<?> klazz) {
try {
return UNSAFE.objectFieldOffset(klazz.getDeclaredField(field));
} catch (NoSuchFieldException e) {
// 将异常转换为相应的错误
NoSuchFieldError error = new NoSuchFieldError(field);
error.initCause(e);
throw error;
}
}
}