美文网首页
原子操作类-数组(volatile+CAS循环;baseOffs

原子操作类-数组(volatile+CAS循环;baseOffs

作者: 王侦 | 来源:发表于2019-07-17 07:05 被阅读0次

    以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循环;baseOffs

          本文链接:https://www.haomeiwen.com/subject/tsrflctx.html