CAS机制的ABA问题及解决

1、什么是ABA问题

ABA问题:就是说一个线程把数据A变成了B,然后又重新变成了A。此时另一个线程读取的时候发现A没有变化,就误以为还是原来的A。

一个ABA例子

public class testABA {
    private static AtomicInteger index=new AtomicInteger(10);
    public static void main(String[] args) {
        new Thread(()->{
            index.compareAndSet(10,11);
            index.compareAndSet(11,10);
            System.out.println(Thread.currentThread().getName()+":10->11->10");
        },"t1").start();

        new Thread(()->{
            try {
                TimeUnit.SECONDS.sleep(2);
                boolean b = index.compareAndSet(10, 12);
                System.out.println(Thread.currentThread().getName()+"index的预期是10吗?"+b
                +"    设置的新值是:"+index.get());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        },"t2").start();
    }
}
//运行结果
t1:10->11->10
t2index的预期是10吗?true设置的新值是:12

2、解决办法AtomicStampedReference

public class testABA {
    private static AtomicInteger index=new AtomicInteger(10);    
    static AtomicStampedReference<Integer> stampref=new AtomicStampedReference<>(10,1);

    public static void main(String[] args) {
        new Thread(()->{
            int stamp=stampref.getStamp();
            System.out.println(Thread.currentThread().getName()+"第一次版本号:"+stamp);
            stampref.compareAndSet(10,11,stampref.getStamp(),stampref.getStamp()+1);
            System.out.println(Thread.currentThread().getName()+"第2次版本号:"+stampref.getStamp());
            stampref.compareAndSet(11,10,stampref.getStamp(),stampref.getStamp()+1);
            System.out.println(Thread.currentThread().getName()+"第3次版本号:"+stampref.getStamp());

        }).start();


        new Thread(()->{
            System.out.println(Thread.currentThread().getName()+"第一次版本号:"+stampref.getStamp());
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            boolean b = stampref.compareAndSet(10, 12, stampref.getStamp(), stampref.getStamp() + 1);
            System.out.println(Thread.currentThread().getName()+" 修改是否成功:"+b+"当前版本号:"+stampref.getStamp()+":当前实际值:"+stampref.getReference());

        }).start();
    }
}
//运行结果
Thread-0第一次版本号:1
Thread-02次版本号:2
Thread-1第一次版本号:2
Thread-03次版本号:3
Thread-1 修改是否成功:true当前版本号:4:当前实际值:12

AtomicStampedReference的cas必须reference和stamp都等于期望值,才会进行修改。因此对于ABA问题,虽然线程2判断reference还是A,但是此时版本号已经不满足要求了。因此并不会执行set。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值