AtomicIntegerArray使用、核心源码解析

1、API方法使用

  • 构造方法
AtomicIntegerArray atomicIntegerArray1 = new AtomicIntegerArray(100);
源码:
private final int[] array;
public AtomicIntegerArray(int var1) {
    this.array = new int[var1];
}
int[] array = {10, 20, 30, 0, 0};
AtomicIntegerArray arr = new AtomicIntegerArray(array);

源码:
private final int[] array;
public AtomicIntegerArray(int[] var1) {
    this.array = (int[])var1.clone();
}

底层就是一个数组。

下面方法使用arr对象进行演示。

 int[] array = {10, 20, 30, 0, 0};
 AtomicIntegerArray arr = new AtomicIntegerArray(array);
  • get(int var1): 获取指定下标的数据
int re = arr.get(1);
System.out.println(re);  //20
  • set(int var1, int var2) 设置指定下标位置的值
  • lazySet(int var1, int var2)
    var1: 数组的下标
    var2: 目标值
arr.set(3,1000);
System.out.println(arr.get(3));  //1000

arr.lazySet(4,2000);
System.out.println(arr.get(4));  //2000
  • length(): 返回数组的长度
System.out.println(arr.length()); //5
  • accumulateAndGet(int var1, int var2, IntBinaryOperator var3) : 设置新值并返回最终结果
    //参数1 数组下标
    //参数2 新值
    //参数3 自定义算法(入参: 原值,新值 。 出参:计算结果)
int i1 = arr.accumulateAndGet(0, 200, (x, y) -> x + y);
System.out.println(i1);  //210
System.out.println(arr.get(0));   //210

源码:
public final int accumulateAndGet(int var1, int var2, IntBinaryOperator var3) {
        long var4 = this.checkedByteOffset(var1);
        int var6;
        int var7;
        do {
			//获取原始值
            var6 = this.getRaw(var4);
            var7 = var3.applyAsInt(var6, var2);
        } while(!this.compareAndSetRaw(var4, var6, var7));

        return var7;
    }
  • compareAndSet(int var1, int var2, int var3) : 给定预期值 若指定位置的原值=预期值 则设置新值反之不进行设置
  • weakCompareAndSet(int var1, int var2, int var3)
    //参数1: 数组下标位置
    //参数2: 预期值
    //参数3: 新值
boolean b = arr.compareAndSet(1, 50, 30);
System.out.println(b);  //false
System.out.println(arr.get(1));  //20

源码:
    public final boolean compareAndSet(int var1, int var2, int var3) {
        return this.compareAndSetRaw(this.checkedByteOffset(var1), var2, var3);
    }
  • decrementAndGet(int var1): 指定位置元素值自减1并且返回最终值
int i = arr.decrementAndGet(1);
System.out.println(i);  //19
System.out.println(arr.get(1));  //19
源码:
public final int decrementAndGet(int var1) {
  return this.getAndAdd(var1, -1) - 1;
}
  
public final int getAndAdd(int var1, int var2) {
    return unsafe.getAndAddInt(this.array, this.checkedByteOffset(var1), var2);
}  

public final int getAndAddInt(Object var1, long var2, int var4) {
   int var5;
   do {
       var5 = this.getIntVolatile(var1, var2);
   } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));

   return var5;
}
  • incrementAndGet(int var1): 指定位置元素值自加1并且返回最终值
int i = arr.incrementAndGet(1);
System.out.println(i);  //21
System.out.println(arr.get(1));  //21
  • getAndAccumulate(int var1, int var2, IntBinaryOperator var3) :设置元素新值并返回原始值
    //参数1: 数组下标
    //参数2: 新值
    //参数3: 函数值计算 ->计算出新值
int andAccumulate = arr.getAndAccumulate(1, 200, (x, y) -> x + y);
System.out.println(andAccumulate);  // 20
System.out.println(arr.get(1));  //220
  • getAndDecrement(int var1): 指定位置元素自减1 并且返回原始值
int andDecrement = arr.getAndDecrement(1);
System.out.println(andDecrement);  //20
System.out.println(arr.get(1));   //19
  • getAndIncrement(int var1) :指定位置元素自加1 并且返回原始值
int andDecrement = arr.getAndIncrement(1);
System.out.println(andDecrement);  //20
System.out.println(arr.get(1));   //21
  • getAndSet(int var1, int var2): 设置新值并返回原始值
int andSet = arr.getAndSet(1, 9000);
System.out.println(andSet);  //20
System.out.println(arr.get(1));  //9000
  • updateAndGet(int var1, IntUnaryOperator var2) :
int i = arr.updateAndGet(1, x -> x + 100);
System.out.println(i);   //120
System.out.println(arr.get(1));  //120
  • updateAndGet(int var1, IntUnaryOperator var2):
int i = arr.updateAndGet(1, x -> x + 100);
System.out.println(i);  //120
System.out.println(arr.get(1)); //120

2、核心源码

AtomicIntegerArray.java
private static final int base;
private static final int shift;

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

base: 对象中int数组的偏移地址
shift: 偏移位数
在这里插入图片描述
cas需要三个参数(绝对地址,期望值,新值),根据绝对地址获取值然后与期望值进行比较,若相等则更新为新值,反之不更新。

数组中指定位置元素的绝对地址如何获取 ?
首先需要直到对象的首地址(绝对地址);
其次需要知道数组的首地址(相对地址,相对对象首地址偏移);
知道数组中每个元素占用的字节,元素占用的字节*元素的下标=元素的偏移地址(相对数组首地址偏移);
上述三个地址之和等于指定位置元素的绝对地址。

base = unsafe.arrayBaseOffset(int[].class): 获取数组的首地址;
int var0 = unsafe.arrayIndexScale(int[].class);: 获取数组中单个元素占用的字节大小;
Integer.numberOfLeadingZeros(var0): 计算出前面有多少个0;
int shift = 31 - Integer.numberOfLeadingZeros(var0); 计算出需要左移多少位;
举例: 假设是int[] 单个元素占用4字节, 第5个元素的首地址应该是(前面有4个元素)
4 * 4 = 16;

此时 var0 = 4
Integer.numberOfLeadingZeros(var0) 前面有29个0;
int shift = 31 - Integer.numberOfLeadingZeros(var0); // = 2
第五个元素; 数组下标=4; 4 << 2 = 16; 效率更高。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值