一、AtomicStampedReference
其实像AtomicBoolean或AtomicLong等这样的变量在多线程修改时,都存在ABA的问题。所谓ABA问题类似于下面伪代码:
第一步 定义一个变量AtomicLong value值为1
第二步 Thread1修改value为2
第三步 Thread2修改value为1
第四步 Thread3通过判断value==1,来检查value是否被修改过
所以Thread3以为value没有被修改过,但实际已经被改过两次了,这就是ABA问题。因此AtomicStampedReference通过引入“版本”的概念,来解决上面的问题。看下面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<T>(reference, stamp);
}
}
private volatile Pair<V> pair;
reference即我们实际存储的变量,stamp是版本,每次修改可以通过+1保证版本唯一性。这样就可以保证每次修改后的版本也会往上递增。伪代码如下
第一步 定义一个变量AtomicStampedReference<Long> Pair.reference值为1, Pair.stamp设置为当前时间curTime
第二步 Thread1执行AtomicStampedReference.compareAndSet(1, 2, curTime, curTime+1)
第三步 Thread2执行AtomicStampedReference.compareAndSet(2, 1, curTime+1, curTime+2)
第四步 Thread3通过判断Pair.reference==1&&Pair.stamp==curTime,发现值虽然没有变,但是已经被修改了两次
二、AtomicMarkableReference
AtomicMarkableReference可以理解为上面AtomicStampedReference的简化版,就是不关心修改过几次,仅仅关心是否修改过。因此变量mark是boolean类型,仅记录值是否有过修改。
private static class Pair<T> {
final T reference;
final boolean mark;
private Pair(T reference, boolean mark) {
this.reference = reference;
this.mark = mark;
}
static <T> Pair<T> of(T reference, boolean mark) {
return new Pair<T>(reference, mark);
}
}
private volatile Pair<V> pair;
网友评论