在学习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 类型的数字,进行比较,因为内存中的地址是一样的。而对于不在缓存范围内的数值,就不可以在通过直接输入数值进行比较了。
解决方案
- 数值类型替换,使用 ar.get()方法获取原对象
- 使用AtomicInteger 代替 AtomicReference 可以使用数值
方案1
方案2