AtomicIntegerArray类详解

    xiaoxiao2023-10-22  31

    介绍

    java.util.concurrent.atomic.AtomicIntegerArray类提供了可以以原子方式读取和写入的底层int数组的操作,还包含高级原子操作。 AtomicIntegerArray支持对底层int数组变量的原子操作。 它具有获取和设置方法,如在变量上的读取和写入。 也就是说,一个集合与同一变量上的任何后续get相关联。 原子compareAndSet方法也具有这些内存一致性功能。

    序号方法描述1public int addAndGet(int i, int delta)原子地将给定的值添加到索引i的元素。2public boolean compareAndSet(int i, int expect, int update)如果当前值==期望值,则将位置i处的元素原子设置为给定的更新值。3public int decrementAndGet(int i)索引i处的元素原子并自减1。4public int get(int i)获取位置i的当前值。5public int getAndAdd(int i, int delta)原子地将给定的值添加到索引i的元素。6public int getAndDecrement(int i)索引i处的元素原子并自减1,并返回旧值。7public int getAndIncrement(int i)将位置i处的元素原子设置为给定值,并返回旧值。8public int getAndSet(int i, int newValue)将位置i处的元素原子设置为给定值,并返回旧值。9public int incrementAndGet(int i)在索引i处以原子方式自增元素。10public void lazySet(int i, int newValue)最终将位置i处的元素设置为给定值。11public int length()返回数组的长度。12public void set(int i, int newValue)将位置i处的元素设置为给定值。13public String toString()返回数组的当前值的String表示形式。14public boolean weakCompareAndSet(int i, int expect, int update)如果当前值==期望值,则将位置i处的元素原子设置为给定的更新值。

    实例

    package main.java.study;

    import java.util.concurrent.atomic.AtomicIntegerArray;

    public class AtomicIntegerArrayTest {

        static class Increment implements Runnable {

            public void run() {             for (int i = 0; i < atomicIntegerArray.length(); i++) {                 int add = atomicIntegerArray.incrementAndGet(i);                 System.out.println("Thread " + Thread.currentThread().getId() + ", index " + i + ", value: " + add);             }         }     }

        static class Compare implements Runnable {

            public void run() {             for (int i = 0; i < atomicIntegerArray.length(); i++) {                 boolean swapped = atomicIntegerArray.compareAndSet(i, 2, 3);                 if (swapped) {                     System.out.println("Thread " + Thread.currentThread().getId() + ", index " + i + ", value: 3");                 }             }         }     }

        private static AtomicIntegerArray atomicIntegerArray = new AtomicIntegerArray(10);

        public static void main(String[] args) throws InterruptedException {         for (int i = 0; i < atomicIntegerArray.length(); i++) {             atomicIntegerArray.set(i, 1);         }

            Thread t1 = new Thread(new Increment());         Thread t2 = new Thread(new Compare());         t1.start();         t2.start();

            t1.join();         t2.join();

            System.out.println("Values: ");         for (int i = 0; i < atomicIntegerArray.length(); i++) {             System.out.print(atomicIntegerArray.get(i) + " ");         }

        }

    }

     

     

    结果

    Thread 11, index 0, value: 3 Thread 10, index 0, value: 2 Thread 10, index 1, value: 2 Thread 10, index 2, value: 2 Thread 10, index 3, value: 2 Thread 10, index 4, value: 2 Thread 10, index 5, value: 2 Thread 10, index 6, value: 2 Thread 10, index 7, value: 2 Thread 10, index 8, value: 2 Thread 10, index 9, value: 2 Values: 3 2 2 2 2 2 2 2 2 2

    源码

    AtomicIntegerArray 的public方法主要是call以下方法

    public class AtomicIntegerArray implements java.io.Serializable {     private static final long serialVersionUID = 2862133569453604235L;

        private static final Unsafe unsafe = Unsafe.getUnsafe();

      //获取数组起始位置的偏移量     private static final int base = unsafe.arrayBaseOffset(int[].class);     private static final int shift;     private final int[] array;

        static {

            //获取数据元素的大小(size),int类型的是 4         int scale = unsafe.arrayIndexScale(int[].class);         if ((scale & (scale - 1)) != 0)             throw new Error("data type scale not a power of two");

          //numberOfLeadingZeros:返回无符号整型i的最高非零位前面的0的个数,int类型(4)的前置0个数为29

         //下面表达式返回位移量,用于计算下标。用于<<操作符,表示乘以2^shift      2^2=4         shift = 31 - Integer.numberOfLeadingZeros(scale);     }

        private long checkedByteOffset(int i) {         if (i < 0 || i >= array.length)             throw new IndexOutOfBoundsException("index " + i);

            return byteOffset(i);     }

      //计算第i个元素的偏移量.

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

        public AtomicIntegerArray(int length) {         array = new int[length];     }

        public AtomicIntegerArray(int[] array) {         // Visibility guaranteed by final field guarantees         this.array = array.clone();     }

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

        private int getRaw(long offset) {         return unsafe.getIntVolatile(array, offset);     }

        public final void set(int i, int newValue) {         unsafe.putIntVolatile(array, checkedByteOffset(i), newValue);     }

        public final void lazySet(int i, int newValue) {         unsafe.putOrderedInt(array, checkedByteOffset(i), newValue);     }

    }

    数组在内存中是连续内存,如下图:

    012…………n-1

     

    Java规定数组中的元素都是相同类型,因此数组中的每个元素的内存大小是相同的,也就是说,只要知道数组的起始位置,我们就可以算出指定下标的数组元素的内存位置

    pos = base(起始位置) + i(下标) * size(类型大小)

     

    最新回复(0)