为什么 AtomicIntegerArray 的 array 成员不是 volatile 而是 final 的啊?

2020-05-10 18:57:29 +08:00
 amiwrong123

对比两个原子类:

public class AtomicIntegerArray implements java.io.Serializable {

    private final int[] array;
    
    public final int get(int i) {
        return getRaw(checkedByteOffset(i));
    }

    private int getRaw(long offset) {
        return unsafe.getIntVolatile(array, offset);
    }
public class AtomicStampedReference<V> {
    private static class Pair<T> {
        final T reference;
        final int stamp;
        private Pair(T reference, int stamp) {
            this.reference = reference;
            this.stamp = stamp;
        }
        static <T> Pair<T> of(T reference, int stamp) {
            return new Pair<T>(reference, stamp);
        }
    }

    private volatile Pair<V> pair;
    
    public V getReference() {
        return pair.reference;
    }

    public int getStamp() {
        return pair.stamp;
    }

第一个问题就是:为什么 AtomicIntegerArray 的 array 成员不是 volatile 而是 final 的啊?为啥这么设计啊

第二个问题就是:为什么 AtomicIntegerArray 的 get 函数不能像 AtomicStampedReference 一样实现呢?是因为成员不是 volatile 的呗。直接像下面这样实现,不行吗。如果改成 private volatile int[] array;,是不是就可以了?

    public final int get(int i) {
        return array[i];  //类似 pair.reference;
    }

各位大佬,求解答啊

2131 次点击
所在节点    Java
7 条回复
hoholiday
2020-05-10 19:10:58 +08:00
了解一下 unsafe 类
luozic
2020-05-10 19:40:51 +08:00
amiwrong123
2020-05-10 19:44:23 +08:00
@hoholiday
了解了啊。要知道大部分原子类,其数据成员都是 volatile 的,其 get 方法都是直接 return 成员,而不是通过 unsafe 对象 get 。
但原子数组类,在设计上就不一样了。
iffi
2020-05-10 20:05:50 +08:00
AtomicIntegerArray 的 set 方法,通过 putIntVolatile 方式修改(修改的是 array 的某个 index 对应的值,不用对整个 array 加 volatile 修饰)
public final void set(int i, int newValue) {
unsafe.putIntVolatile(array, checkedByteOffset(i), newValue);
}

AtomicStampedReference 的 set 方法,直接=赋值修改,并发情况下,为了内存可见性采用 volatile 修饰
public void set(V newReference, int newStamp) {
Pair<V> current = pair;
if (newReference != current.reference || newStamp != current.stamp)
this.pair = Pair.of(newReference, newStamp);
}
amiwrong123
2020-05-10 20:20:08 +08:00
@iffi
那如果修改 AtomicIntegerArray 为 private volatile int[] array,再修改 set 函数为 public final void set(int i, int newValue) {array[i] = newValue; } 。

这样是否可以保证 可见性 呢
iffi
2020-05-10 20:38:02 +08:00
@amiwrong123 这个 array 创建好了之后,不会修改其引用指向,所以 private volatile int[] array 不符合语义。修改 set 函数为 public final void set(int i, int newValue) {array[i] = newValue; } 我猜不会保证可见性(你也可以复制 JDK 的源码修改并自己实验验证一下),除非对 array 每一个元素都加 volatile 修饰。这也是为什么要用 unsafe.putIntVolatile(array, checkedByteOffset(i), newValue);
SoloCompany
2020-05-11 22:36:56 +08:00
你需要的是 AtomicReference 而不是 AtomicXxxArray

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/670310

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX