AtomicIntegerArray

这个类是对数组类型 int[] 的包装,提供的能力是对数据中某个元素的原子更新能力,它的方法是基于某个元素的偏移量完成的,我们只看看元素的定位的部分:

public class AtomicIntegerArray implements java.io.Serializable {
    // ...
    private static final int base = unsafe.arrayBaseOffset(int[].class);
    private static final int shift;
    private final int[] array;

    static {
        int scale = unsafe.arrayIndexScale(int[].class);
        if ((scale & (scale - 1)) != 0)
            throw new Error("data type scale not a power of two");
        shift = 31 - Integer.numberOfLeadingZeros(scale);
    }

    private static long byteOffset(int i) {
        return ((long) i << shift) + base;
    }

    // ...

我们看到数组的定位 byteOffset 等于 base + scale * N,我们通过 jol 库打印

System.out.println(ClassLayout.parseClass(int[].class).toPrintable());
Unsafe unsafe = getUnsafe();
System.out.println(unsafe.arrayBaseOffset(int[].class));
System.out.println(unsafe.arrayIndexScale(int[].class));

得到结果:

[I object internals:
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0    16        (object header)                           N/A
     16     0    int [I.<elements>                             N/A
Instance size: 16 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
16 // base = 16
4  // scale = 4

base 代表数组中第一个元素的偏移量,这里 16 代表了对象头信息,scale 代表每个元素的大小,一个 int 默认是 4 个字节。

代码中的 scale & (scale - 1) 是很趣的 Hack,用来判断一个数是否为 2 的次方。

另一个细节是代码中将 scale 转换成了 shift,并用 i << shift 计算偏移量,一般来说位移操作会比乘法快。