原子操作类-数组(volatile+CAS循环;baseOffset + i*indexScale)

以AtomicIntegerArray为例。

1.构造器和域

    private static final int base = unsafe.arrayBaseOffset(int[].class);
    private static final int shift;
    private final int[] array;
public AtomicIntegerArray(int length) {
        array = new int[length];
    }
    public AtomicIntegerArray(int[] array) {
        // Visibility guaranteed by final field guarantees
        this.array = array.clone();
    }

2.方法

2.1 采用baseOffset + i*indexScale获取数组第i个元素

    public final int get(int i) {
        return getRaw(checkedByteOffset(i));
    }

    private int getRaw(long offset) {
        return unsafe.getIntVolatile(array, offset);
    }
    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 long checkedByteOffset(int i) {
        if (i < 0 || i >= array.length)
            throw new IndexOutOfBoundsException("index " + i);

        return byteOffset(i);
    }

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

arrayBaseOffset,获取数组第一个元素的偏移地址。arrayIndexScale,数组中元素的大小,占用多少个字节。arrayBaseOffset与arrayIndexScale配合起来使用,就可以定位数组中每个元素在内存中的位置。

floor(log2(x)) = 31 - numberOfLeadingZeros(x)

如果这是一个int型数组,indexScale 等于4,那么 shift 值为2,所以乘以4和向左移2位,结果是一样的。

    public final int getAndSet(int i, int newValue) {
        return unsafe.getAndSetInt(array, checkedByteOffset(i), newValue);
    }

采用的也是CAS循环,转换为偏移量后,与AtomicInteger没有区别。

3.使用函数接口

    public final int getAndUpdate(int i, IntUnaryOperator updateFunction) {
        long offset = checkedByteOffset(i);
        int prev, next;
        do {
            prev = getRaw(offset);
            next = updateFunction.applyAsInt(prev);
        } while (!compareAndSetRaw(offset, prev, next));
        return prev;
    }
    public final int getAndAccumulate(int i, int x,
                                      IntBinaryOperator accumulatorFunction) {
        long offset = checkedByteOffset(i);
        int prev, next;
        do {
            prev = getRaw(offset);
            next = accumulatorFunction.applyAsInt(prev, x);
        } while (!compareAndSetRaw(offset, prev, next));
        return prev;
    }

你可能感兴趣的:(原子操作类-数组(volatile+CAS循环;baseOffset + i*indexScale))