Java并发CAS之ABA问题

CAS锁有ABA问题

因为CAS是乐观锁,只要预期值和当前值相同则可以修改成功,但是这会有个"ABA"问题.
什么是"ABA"问题呢,我上段程序就知道了

public class AtomicReferenceDemo {
    static  AtomicReference<Integer> atomicReference = new AtomicReference<>(100);
    static AtomicStampedReference<Integer> stampedReference = new AtomicStampedReference<>(100,1);
    public static void main(String[] args) {
        System.out.println("ABA问题的演示~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
        new Thread(() -> {
            //把值修改为101 再改为100
            boolean b = atomicReference.compareAndSet(100, 101);
            System.out.println(b+","+Thread.currentThread().getName()+"第一次修改值为"+atomicReference);
            b = atomicReference.compareAndSet(101,100);
            System.out.println(b+","+Thread.currentThread().getName()+"第二次修改值为"+atomicReference);

        },"t1").start();

        new Thread(() -> {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            boolean b = atomicReference.compareAndSet(100, 2020);
            System.out.println(b+ ","+Thread.currentThread().getName() +"修改值为"+atomicReference.get());

        },"t2").start();
    }
}

初始值就为100
上面这段程序t1和t2线程,t1线程修改值两次,第一次修改时预期值100,希望改为101,第二次预期值101,希望改为100,其实t1线程干的就是"ABA"操作.
t2线程一来看预期值100对上了,然后修改为2020,看上去是不是很和谐呢.这就是"ABA"问题,t1线程干了一波事情,神不知鬼不觉
控制台输出如下
在这里插入图片描述

ABA问题的解决

ABA问题解决也很简单,就是版本号的思路,修改一次版本号自增一次,虽然值还是那个值,但是版本号却一直在变.直接上段程序就清楚了
需要用到 AtomicStampedReference这个类,时间戳原子类

public class AtomicReferenceDemo {
    static  AtomicReference<Integer> atomicReference = new AtomicReference<>(100);
    static AtomicStampedReference<Integer> stampedReference = new AtomicStampedReference<>(100,1);
    public static void main(String[] args) {
        System.out.println("演示利用版本号解决ABA问题~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");

        new Thread(() -> {
            int stamp = stampedReference.getStamp();
            System.out.println(Thread.currentThread().getName()+"第一次版本号:"+stamp);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            boolean b = stampedReference.compareAndSet(100, 101, stampedReference.getStamp(),
                    stampedReference.getStamp() + 1);
            System.out.println(b+ ","+Thread.currentThread().getName() +"修改值为"+stampedReference.getReference()+",版本号为"+stampedReference.getStamp());

            b = stampedReference.compareAndSet(101, 100, stampedReference.getStamp(),
                    stampedReference.getStamp() + 1);
            System.out.println(b+ ","+Thread.currentThread().getName() +"修改值为"+stampedReference.getReference()+",版本号为"+stampedReference.getStamp());
        },"t4").start();

        new Thread(() -> {
            int stamp = stampedReference.getStamp();
            System.out.println(Thread.currentThread().getName()+"第一次版本号:"+stamp);
            try {
                Thread.sleep(4000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            boolean b = stampedReference.compareAndSet(100, 2020, stamp, stampedReference.getStamp() + 1);
            System.out.println(b+ ","+Thread.currentThread().getName() +"当前版本号:"+stamp+"修改值为"+stampedReference.getReference()+",版本号为"+stampedReference.getStamp());

        },"t5").start();

    }
}

这段程序是t4和t5两个线程,t4干了一波ABA操作,但是版本号出卖了它,t5线程一看预期值100希望修改为2020,预期值确实符合,但是版本号1和当前版本号3一比对就漏出破绽了,于是修改失败.
输出结果如下
在这里插入图片描述

总结

ABA问题可以使用版本号解决
ABA问题主要细分为两个点
1.会有没必要的资源开销
2.数据会丢失覆盖的问题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值