ABA问题基础及解决

一.ABA问题的产生

二.AtomicReference原子引用

三.AtomicStampedReference版本号原子引用

四.ABA问题解决

前面的内容之间的关联:CAS->Unsafe类->CAS思想->ABA问题->如何解决ABA问题

一.ABA问题的产生(狸猫换太子)

1)线程1和线程2开启时,按照之前讲述的对线程变量的操作,把主内存的值A复制到线程中的工作内存A

2)线程1需要10s,线程2需要2s,假设线程2先修改则线程2中的工作内存的值A和主内存中的值A修改为B

3)等待线程1的过程中,线程2又把自己内存中的值和主内存中的值修改为“A”

4)此时线程1开启,发现线程1中的A与主内存中的“A”相同,按照CAS的方法把值修改为B

简单的来说就是由于线程1和线程2存在时间差,线程2执行完之后又执行了一次改回来”原来的“值,线程1认为和自己的值相同,则又进行了操作。

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAI0hhc2hNYXAj,size_20,color_FFFFFF,t_70,g_se,x_16

 二.AtomicReference原子引用

public class AtomicReferenceDemo {
    public static void main(String[] args) {
        User lzm = new User("lzm", 18);
        User lin = new User("lin", 20);
        AtomicReference<User> atomicReference = new AtomicReference<>();
        atomicReference.set(lzm);
        System.out.println(atomicReference.compareAndSet(lzm, lin)); // true
        System.out.println(atomicReference.get()); // User(userName=lin, age=20)
    }
}
class User{
    String userName;
    int age;
}

 三.AtomicStampedReference版本号原子引用

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAI0hhc2hNYXAj,size_20,color_FFFFFF,t_70,g_se,x_16

 线程A和线程B初始值都为100,版本号都为1,假设线程A先执行,此时线程B挂起,线程A的值把100修改为101,此时版本号加1变为2,由于时间差,线程A又把值101修改为100,此时版本号继续加1变为3,主内存的值为“100”;此时线程B开启,线程B工作内存的值100与主内存中的“100”对比发现相同则进行修改操作,此时版本号变为2.这个过程中虽然修改成功但是线程B和主内存中100并非相同,主内存的值被狸猫换太子了,通过版本号就可清晰看出。

 四.ABA问题解决

增加版本号

public class ABADemo2 {
    private static AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<>(100, 1);

    public static void main(String[] args) {
        new Thread(() -> {
            //获得版本号为1
            int stamp = atomicStampedReference.getStamp();
            System.out.println(Thread.currentThread().getName() + " 的版本号为:" + stamp);
            //睡眠1s是为了执行下面的一个线程使得版本号都为1开始
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //100修改为101再修改为100 产生ABA问题 每次修改版本号加1
            atomicStampedReference.compareAndSet(100, 101, atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1 );//版本号为2
            atomicStampedReference.compareAndSet(101, 100, atomicStampedReference.getStamp(), atomicStampedReference.getStamp() + 1 );//版本号为3
        }).start();

        new Thread(() -> {
            //获得版本号为1
            int stamp = atomicStampedReference.getStamp();
            System.out.println(Thread.currentThread().getName() + " 的版本号为:" + stamp);
            //睡眠3s是为了让上面的线程先执行完 产生ABA
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            由于上面的线程版本号为3 这个线程版本号为2 所以返回false
            boolean b = atomicStampedReference.compareAndSet(100, 2020, stamp, stamp + 1);
            System.out.println(b); // false
            System.out.println(atomicStampedReference.getReference()); // 100
        }).start();
    }

 

 

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

#HashMap#

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值