解决ABA问题,原子引用
整体思想是乐观锁。
一般的实现乐观锁的方式就是记录数据版本。
线程在提交前,根据版本号来判断是否冲突。
看代码:
package com.cc.cas;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicStampedReference;
public class CASDemo {
static AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<>(1,1);
public static void main(String[] args) {
new Thread(()->{
//获得版本号
int stamp = atomicStampedReference.getStamp();
System.out.println("A1=>" + stamp);
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(atomicStampedReference.compareAndSet(1, 2,
atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1));
System.out.println("A2=>" + atomicStampedReference.getStamp());
System.out.println(atomicStampedReference.compareAndSet(2, 1,
atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1));
System.out.println("A3=>" + atomicStampedReference.getStamp());
},"A").start();
new Thread(()->{
//获得版本号
int stamp = atomicStampedReference.getStamp();
System.out.println("B1=>" + stamp);
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(atomicStampedReference.compareAndSet(1,6,stamp,stamp+1));
System.out.println("B2=>" + atomicStampedReference.getStamp());
},"B").start();
}
}
运行结果:
A1=>1
B1=>1
true
A2=>2
true
A3=>3
false
B2=>3
可看到最后false,B2获得的版本号为3了,通过版本号知道值被线程A改过。
这里要注意一个问题:
AtomicStampedReference,如果泛型是包装类,注意对象的引用。
Integer 使用了对象缓存机制,默认范围是 -128 ~ 127 ,推荐使用静态工厂方法 valueOf 获取对象实例,而不是new,因为 valueOf 使用缓存,而 new 一定会创建新的对象分配新的内存空间;