什么是CAS?
CAS即对比交换,它在保证数据原子性的前提下尽可能的减少了锁的使用
ABA问题
线程1准备用CAS修改变量值A,在此之前,其它线程将变量的值由A替换为B,又由B替换为A,然后线程1执行CAS时发现变量的值仍然为A,所以CAS成功。但实际上这时的现场已经和最初不同了。
例子
private static void atomicIntegerABA() {
Thread main = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("操作线程" + Thread.currentThread() + ",初始值 = " + atomicInteger); //定义变量 a = 1
try {
Thread.sleep(1000); //等待1秒 ,以便让干扰线程执行
} catch (InterruptedException e) {
e.printStackTrace();
}
boolean isCASSuccess = atomicInteger.compareAndSet(1, 2); //CAS操作
System.out.println("操作线程" + Thread.currentThread() + ",CAS操作结果: " + isCASSuccess);
}
}, "主操作线程");
Thread other = new Thread(new Runnable() {
@Override
public void run() {
Thread.yield(); //确保thread-main线程优先执行
atomicInteger.incrementAndGet(); // a 加 1, a + 1 = 1 + 1 = 2
System.out.println("操作线程" + Thread.currentThread() + ",【increment】 ,值 = " + atomicInteger);
atomicInteger.decrementAndGet(); // a 减 1, a - 1 = 2 - 1 = 1
System.out.println("操作线程" + Thread.currentThread() + ",【decrement】 ,值 = " + atomicInteger);
}
}, "干扰线程");
main.start();
other.start();
}
输出结果
操作线程Thread[主操作线程,5,main],初始值 = 1
操作线程Thread[干扰线程,5,main],【increment】 ,值 = 2
操作线程Thread[干扰线程,5,main],【decrement】 ,值 = 1
操作线程Thread[主操作线程,5,main],CAS操作结果: true
解决ABA方案
思路
解决ABA最简单的方案就是给值加一个修改版本号,每次值变化,都会修改它版本号,CAS操作时都对比此版本号。
JAVA中ABA中解决方案(AtomicStampedReference)
AtomicStampedReference主要维护包含一个对象引用以及一个可以自动更新的整数"stamp"的pair对象来解决ABA问题。
private static void atomicStampedRefABA() {
int stamp = atomicStampedRef.getStamp(); //获取当前标识别
Thread main = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("操作线程" + Thread.currentThread() + ",初始值 = " + atomicStampedRef.getReference()); //定义变量 a = 1
try {
Thread.sleep(1000); //等待1秒 ,以便让干扰线程执行
} catch (InterruptedException e) {
e.printStackTrace();
}
boolean isCASSuccess = atomicStampedRef.compareAndSet(1, 2, stamp, stamp + 1); //CAS操作
System.out.println("操作线程" + Thread.currentThread() + ",CAS操作结果: " + isCASSuccess);
}
}, "主操作线程");
Thread other = new Thread(new Runnable() {
@Override
public void run() {
Thread.yield(); //确保thread-main线程优先执行
atomicStampedRef.compareAndSet(1, 2, stamp, stamp + 1);
System.out.println("操作线程" + Thread.currentThread() + ",【increment】 ,值 = " + atomicStampedRef.getReference());
atomicStampedRef.compareAndSet(2, 1, stamp, stamp + 1);
System.out.println("操作线程" + Thread.currentThread() + ",【decrement】 ,值 = " + atomicStampedRef.getReference());
}
}, "干扰线程");
main.start();
other.start();
}
输出结果
操作线程Thread[主操作线程,5,main],初始值 = 1
操作线程Thread[干扰线程,5,main],【increment】 ,值 = 2
操作线程Thread[干扰线程,5,main],【decrement】 ,值 = 2
操作线程Thread[主操作线程,5,main],CAS操作结果: false