文章40 | 阅读 14786 | 点赞0
在我们使用CAS操作的时候会有一个问题那就是CAS过程中,预期值可能被更新了多次,最终又更新会预期值,这样判断cas操作则是成功的因为本次cas操作符合条件。
AtomicStampedReference总的来说就是解决一个线程将A改成C,也就是说当前值是A。
但是会出现A被改成B后又改回A,那么A改成C还是成功的。有些时候是不允许这种情况。因此有了AtomicStampedReference类,它在CAS的基础上加了一个时间戳的概念,实际上就是在原先需要预期值和新值,两个参数,现在需要另外加两个参数也就是预期版本号、更新后的版本号。如果预期值或预期版本号其中一个不符合就会更新失败。
weakCompareAndSet()
或者compareAndSet()
两者效果一致getReference()
getStamp()
attemptStamp(预期版本号 , 新版本号)
无条件更新
当前值和当前版本号set( 新值, 新版本号 )
get(int[] stampHolder)
当前值通过返回值得到,当前版本号则在stampHolder[0]
中另外一个相识的类 AtomicMarkableReference
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
public class AtomicStampedReference<V> {
private static class Pair<T> {
final T reference; // 当前值
final int stamp; // 当前时间戳
private Pair(T reference, int stamp) {
this.reference = reference;
this.stamp = stamp;
}
// 得到一个Pair实例
static <T> Pair<T> of(T reference, int stamp) {
return new Pair<T>(reference, stamp);
}
}
private volatile Pair<V> pair;
private static final VarHandle PAIR;
static {
try {
MethodHandles.Lookup l = MethodHandles.lookup();
PAIR = l.findVarHandle(AtomicStampedReference.class, "pair", Pair.class);
} catch (ReflectiveOperationException e) {
throw new ExceptionInInitializerError(e);
}
}
private boolean casPair(Pair<V> cmp, Pair<V> val) {
return PAIR.compareAndSet(this, cmp, val);
}
/** * 创建一个有初始值和初始版本号的AtomicStampedReference实例 */
public AtomicStampedReference(V initialRef, int initialStamp) {
pair = Pair.of(initialRef, initialStamp);
}
/** * 返回当前值 */
public V getReference() {
return pair.reference;
}
/** * 返回当前版本号 */
public int getStamp() {
return pair.stamp;
}
/** * 返回当前值并将数组中的时间戳更新为当前的时间戳 */
public V get(int[] stampHolder) {
Pair<V> pair = this.pair;
stampHolder[0] = pair.stamp;
return pair.reference;
}
/** * cas操作,多个期望的时间戳和更新后的时间戳两个参数 */
public boolean weakCompareAndSet(V expectedReference, V newReference, int expectedStamp, int newStamp) {
return compareAndSet(expectedReference, newReference, expectedStamp, newStamp);
}
/** * cas操作被上面方法调用,意味着两个方法效果一致 */
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)));
}
/** * 无条件的更新当前值和当前时间戳 */
public void set(V newReference, int newStamp) {
Pair<V> current = pair;
if (newReference != current.reference || newStamp != current.stamp)
this.pair = Pair.of(newReference, newStamp);
}
/** * 如果是预期值则更新时间戳 */
public boolean attemptStamp(V expectedReference, int newStamp) {
Pair<V> current = pair;
return
expectedReference == current.reference &&
(newStamp == current.stamp ||
casPair(current, Pair.of(expectedReference, newStamp)));
}
}
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://yumbo.blog.csdn.net/article/details/109634769
内容来源于网络,如有侵权,请联系作者删除!