AtomicReference compareAndSet 返回false的原因分析

本文探讨了在使用AtomicReference持有Integer对象时遇到的问题,即当修改超出Integer缓存范围的数值时,修改无效。原因是Integer对象在缓存范围内会复用相同值的对象,导致引用比较失败。解决方案包括使用ar.get()获取原对象进行比较或改用AtomicInteger。文章通过代码示例和调试分析解释了问题的原因,并提供了两种可行的解决策略。
摘要由CSDN通过智能技术生成

在学习AtomicReference的过程中,在进行小测试的时候,遇到了一个问题,对于超过缓存范围(-128-127)内的Integer数值类型进行修改时修改无效。
demo代码如下:

 AtomicReference<Integer> ar = new AtomicReference<>(100);
        new Thread(() -> {
            String name = Thread.currentThread().getName();
            ar.compareAndSet(100, 200);
            ar.compareAndSet(200, 100);
            System.out.println(name + " 两次修改之后的值:" + ar.get());
        }).start();

        new Thread(() -> {
            try {
                Thread.sleep(1000);
                String name = Thread.currentThread().getName();
                ar.compareAndSet(100, 200);
                System.out.println(name + " 第三次修改之后的值:" + ar.get());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();

执行结果:

在这里插入图片描述
对于在Integer缓存范围内的数值进行修改时却没有问题,将上面代码中的 200 改为 127 时,代码如下:

AtomicReference<Integer> ar = new AtomicReference<>(100);
        new Thread(() -> {
            String name = Thread.currentThread().getName();
            ar.compareAndSet(100, 127);
            ar.compareAndSet(127, 100);
            System.out.println(name + " 两次修改之后的值:" + ar.get());
        }).start();

        new Thread(() -> {
            try {
                Thread.sleep(1000);
                String name = Thread.currentThread().getName();
                ar.compareAndSet(100, 127);
                System.out.println(name + " 第三次修改之后的值:" + ar.get());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();

结果:

在这里插入图片描述
基于第一种情况,进行断点调试,发现第一个线程执行的第一个compareAndSet 返回true,第二个返回为false。
在这里插入图片描述
在这里插入图片描述

进一步给compareAndSet 方法进行打一个断点进行调试。

在这里插入图片描述

从方法注释上可知,比较是通过 == 进行比较的,而对于引用数据类型 == 比较的是内存中的地址。
第一次比较时 期望值 except 为100,在integer 的缓存范围内,与 ar 对象中的值 100 所指向的内存地址是一样的,所以第一次可以修改成功。从100 修改为200

在这里插入图片描述
第二次修改时,期望值 expcpt 为 200 ,不在Integer 的缓存范围,与 ar 对象中的值 200 虽然值相等,但是内存中的地址不同,所以返回为 false。

之所以出现上面那种情况,就是因为 Integer 存在缓存,所以在缓存范围内的Integer 数值,可以通过直接输入 Integer 类型的数字,进行比较,因为内存中的地址是一样的。而对于不在缓存范围内的数值,就不可以在通过直接输入数值进行比较了。

解决方案

  1. 数值类型替换,使用 ar.get()方法获取原对象
  2. 使用AtomicInteger 代替 AtomicReference 可以使用数值

方案1
在这里插入图片描述
方案2

在这里插入图片描述

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值