最近有小伙伴问到我CAS存在的ABA问题,所以写个博客记录一下,话不多说直接上代码:
存在的ABA问题:
/*
创建一个AtomicReference 用来实现CAS的ABA问题,默认值为100
*/
static AtomicReference<Integer> atomicReference = new AtomicReference<>(100);
我们使用JUC原子类方法AtomicReference(V initialvalue)来演示CAS存在的ABA问题:
public static void atomicReferenceStudent() {
/*
线程T1执行
atomicReference.compareAndSet(期望值, 更新值);
若atomicReference的值与期望值匹配,则进行更新。
*/
new Thread(() -> {
atomicReference.compareAndSet(100, 101);
atomicReference.compareAndSet(101, 100);
}, "T1").start();
/*
线程T2执行
*/
new Thread(() -> {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
/*
当前执行是否成功:true,当前值为:2022
打印表示出T2执行成功,说明产生了ABA问题,因为内存值已经被线程T1修改了,说明了CAS的原子引用操作是只看重头和尾不关心过程的
*/
System.out.println("当前执行是否成功:" + atomicReference.compareAndSet(100, 2022) + ",当前值为:" + atomicReference.get());
}, "T2").start();
}
调用main方法查看打印结果:
//启动类
public static void main(String[] args) {
atomicReferenceStudent();
}
打印结果:
当前执行是否成功:true,当前值为:2022
如何解决ABA问题:
/*
创建一个AtomicStampedReference代替AtomicReference 用来解决CAS的ABA问题,默认值为100,版本号默认值为1
*/
static AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<>(100, 1);
我们使用JUC原子类AtomicStampedReference(V initialRef, int initialStamp)用来解决CAS的ABA问题:
public static void atomicStampedReferenceStudent() {
//获取版本号,默认版本号为1
int stamp = atomicStampedReference.getStamp();
new Thread(() -> {
//线程拿到版本号为1的内存值100,符合期望值,将值更新为101,版本号+1,本次操作完成后版本号为2的内存值101
atomicStampedReference.compareAndSet(100, 101, stamp, atomicStampedReference.getStamp() + 1);
//线程拿到版本号为2的内存值101,符合期望值,将值更新为101,版本号+1,本次操作完成后版本号为3的内存值100
atomicStampedReference.compareAndSet(101, 100, atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1);
}, "T1").start();
try {
Thread.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() ->
//线程拿到版本号为1的内存值100,符合期望值,但版本号不一致,内存值已被操作,则本次操作失败
System.out.println("当前执行是否成功:" + atomicStampedReference.compareAndSet(100, 2022, stamp, atomicStampedReference.getStamp() + 1) +
",当前值为:" + atomicStampedReference.getReference() +
",当前版本号为:" + atomicStampedReference.getStamp()), "T2").start();
}
调用main方法打印结果:
//启动类
public static void main(String[] args) {
atomicStampedReferenceStudent();
}
打印结果:
当前执行是否成功:false,当前值为:100,当前版本号为:3
好了,目前就介绍到这里,谢谢您的观看,若有问题欢迎留言一起讨论~