在Hesey的《用ATOMICSTAMPEDREFERENCE解决ABA问题》疑问中,使用了一个非常具有表达力的例子。
-
有一个栈(单链表实现)如下所示:
a.next = b, b.next = null栈顶元素为A,现在Thread1准备将栈顶元素变为B,而在此时Thread2执行了以下操作,将A、B出栈,并且将A、C、D入栈,此时栈为
此时线程发现栈顶为A(但是此时的A已经不是原来的A),于是Thread1将栈顶元素改为b ,此时结构为C、D丢失,栈中只有元素B
如何解决?
在java中,使用AtomicStampedRefrece进行版本戳标记 对应上例中初始状态A1.next = B2, 线程2更新后,C4.next = D3, A5.next = C4 线程1工作,A5 != A1,更新失败。
代码示例
以下代码分别演示了AtomicInteger和AtomicStampedReference的1结果。
class Test{
private static AtomicInteger atomicInt = new AtomicInteger(100);
private static AtomicStampedReference atomicStampedRef = new AtomicStampedReference(100, 0);
public static void main(String[] args) throws InterruptedException {
Thread intT1 = new Thread(new Runnable() {
@Override
public void run() {
atomicInt.compareAndSet(100, 101);
atomicInt.compareAndSet(101, 100);
}
});
Thread intT2 = new Thread(new Runnable() {
@Override
public void run() {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
}
boolean c3 = atomicInt.compareAndSet(100, 101);
System.out.println(c3); // true
System.out.println(atomicInt); // 101
}
});
intT1.start();
intT2.start();
intT1.join();
intT2.join();
System.out.println("==============");
Thread refT1 = new Thread(new Runnable() {
@Override
public void run(){
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
System.out.println("****");
}
atomicStampedRef.compareAndSet(100, 101, atomicStampedRef.getStamp(), atomicStampedRef.getStamp() + 1);
atomicStampedRef.compareAndSet(101, 100, atomicStampedRef.getStamp(), atomicStampedRef.getStamp() + 1);
};
});
Thread refT2 = new Thread(new Runnable() {
@Override
public void run() {
int stamp = atomicStampedRef.getStamp();
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
}
boolean c3 = atomicStampedRef.compareAndSet(100, 101, stamp, stamp + 1);
System.out.println(c3); // false
System.out.println(atomicStampedRef.getReference()); // 100, CAS失败
}
});
refT1.start();
refT2.start();
refT1.join();
refT2.join();
}
}