什么是ABA问题?被换过两次,表面上还是A,其实中间换过一次
举个ABA在现实生活中的例子?
用代码展示ABA问题
public class singleton {
public static void main(String[] args) {
AtomicReference num=new AtomicReference(100);
new Thread(()->{
num.compareAndSet(100,101);
num.compareAndSet(101,100);
},"t1").start();
new Thread(()->{
try {
//强行让t2线程睡眠是为了完成上面的ABA操作
Thread.sleep(1000);
num.compareAndSet(100,105);
} catch (InterruptedException e) {
e.printStackTrace();
}
},"t2").start();
//这样不用计算睡眠时间,这要大于两个活跃线程就让主线程礼让
while(Thread.activeCount()>2)
{
Thread.yield();
}
System.out.println(num);
}
}
如何解决ABA问题?
利用atomicStampedReference来解决ABA问题,本质是利用版本号
public class singleton {
public static void main(String[] args) {
//第一个是初始值,第二个是初始值是版本号
AtomicStampedReference<Integer> num=new AtomicStampedReference<>(100,1);
new Thread(()->{
//这个sleep的时间是为了让t2线程有时间读取版本号
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//第一个参数是当前值,第二个值是如果比较成功后的修改值,第三个值是当前版本号,第四个是修改后的版本号
num.compareAndSet(100,101,num.getStamp(),num.getStamp()+1);
num.compareAndSet(101,100,num.getStamp(),num.getStamp()+1);
},"t1").start();
new Thread(()->{
int stamp=num.getStamp();
//这个睡眠时间是为了去执行线程T1,完成ABA
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
boolean flag=num.compareAndSet(100,2019,stamp,stamp+1);
System.out.println(flag);
},"t2").start();
}
}
CAS还会带来什么问题?
A. 自旋的话,CPU的占用率会过高
B.只能保证一个共享变量的原子操作