【Java源码计划】AtomicIntegerArray<
2019-04-03 本文已影响1人
DeanChangDM
AtomicIntegerArray
这个类是Atomic包下的类,用于提供对应类型的原子操作
跟其他的类一样,这个类提供了对整形数组的原子更新操作
首先是一些初始化相关内容
//初始化Unsafe
private static final Unsafe unsafe = Unsafe.getUnsafe();
//记录数组的base地址
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);
//判断偏移位数是不是2的幂
if ((scale & (scale - 1)) != 0)
throw new Error("data type scale not a power of two");
//计算并初始化移位操作的位数
//numberOfLeadingZeros的作用是
//返回无符号整型scale的最高非零位前面的0的个数,包括符号位在内
//也就是说如果为负数,这个方法将会返回0,符号位为1
//这个方法具体的放到对应的位置再说
//整形32位,去掉0的位数后,也就是取得了移位操作需要的位数
shift = 31 - Integer.numberOfLeadingZeros(scale);
}
//这个方法有两个作用,第一校验边界,然后将偏移量转换为byte
public AtomicIntegerArray(int length) {
array = new int[length];
}
private long checkedByteOffset(int i) {
if (i < 0 || i >= array.length)
throw new IndexOutOfBoundsException("index " + i);
return byteOffset(i);
}
//方法用于转换偏移量,将整形的转换为byte的偏移量
private static long byteOffset(int i) {
return ((long) i << shift) + base;
}
//用给定的长度创建一个AtomicIntegerArray
public AtomicIntegerArray(int length) {
array = new int[length];
}
//用给定的数组初始化一个AtomicIntegerArray
//长度跟给定的数组一样,并且所有元素都来自于这个数组
public AtomicIntegerArray(int[] array) {
// 注意这个字段的可见性是由final field的特性提供的
// 因为这个字段只能初始化一次
this.array = array.clone();
}
下面是一些数组的常见方法和一些关键的读写操作
//返回数组的长度
public final int length() {
return array.length;
}
//返回给定索引的元素
public final int get(int i) {
//注意结合上面的checkedByteOffset和下面的getRaw
return getRaw(checkedByteOffset(i));
}
//根据给定的偏移量,读取数组元素
private int getRaw(long offset) {
return unsafe.getIntVolatile(array, offset);
}
//将给定的元素设置到给定的索引位置上
public final void set(int i, int newValue) {
//注意此处利用了checkedByteOffset将索引转换为了偏移量
unsafe.putIntVolatile(array, checkedByteOffset(i), newValue);
}
//作用和上面的方法一样,区别在于只能保证最终会把指定索引的元素设置为给定元素
public final void lazySet(int i, int newValue) {
unsafe.putOrderedInt(array, checkedByteOffset(i), newValue);
}
//将给定变量原子性的设置到指定索引位置,然后返回原来的元素
public final int getAndSet(int i, int newValue) {
return unsafe.getAndSetInt(array, checkedByteOffset(i), newValue);
}
//CAS操作,原子性的设置i的元素,当期望值和当前值相等,将update元素设置进去
public final boolean compareAndSet(int i, int expect, int update) {
return compareAndSetRaw(checkedByteOffset(i), expect, update);
}
//实际的CAS操作方法,将索引转换为了偏移量
private boolean compareAndSetRaw(long offset, int expect, int update) {
return unsafe.compareAndSwapInt(array, offset, expect, update);
}
//作用跟上面的一样
//但是作为weak的方法,跟其他的weak方法一样可能出现不明确的failed,
//所以通常不能作为compareAndSet的替代使用
public final boolean weakCompareAndSet(int i, int expect, int update) {
return compareAndSet(i, expect, update);
}
下面是对getAndAdd方法的一些应用
//原子性的实现给定索引位置的元素的自增
public final int getAndIncrement(int i) {
return getAndAdd(i, 1);
}
//同上,只是作用上是自减
public final int getAndDecrement(int i) {
return getAndAdd(i, -1);
}
//上面自增和自减的实际执行方法,原子性的对指定元素增加指定的大小,然后返回之前的元素
public final int getAndAdd(int i, int delta) {
return unsafe.getAndAddInt(array, checkedByteOffset(i), delta);
}
//本质上还是对getAnd的应用,作用是自增后返回更新的元素
public final int incrementAndGet(int i) {
return getAndAdd(i, 1) + 1;
}
//本质上是对getAndAdd应用,作用是自减后返回更新的元素
public final int decrementAndGet(int i) {
return getAndAdd(i, -1) - 1;
}
//给定索引增加delta,并返回更新后的元素
public final int addAndGet(int i, int delta) {
return getAndAdd(i, delta) + delta;
}
下面是一些1.8之后新增的方法,主要和函数式变成有关
//原子性的对给定未知的元素增加给定函数执行结果
//注意,给定函数必须是无副作用的,因为在进行CAS操作时如果失败了
//这个方法可能会再次执行
//方法返回之前的元素
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 updateAndGet(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 next;
}
//更加通用的方法,想必须前面两个方法,这个方法是把i对应位置上得知设置为
//给定函数执行(当前元素为第一个参数,x为第二个参数)后的结果
public final int accumulateAndGet(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 next;
}
最后是比较常见的tostring方法
public String toString() {
//索引最大位置
int iMax = array.length - 1;
//最大索引位置不合法显示空的数组
if (iMax == -1)
return "[]";
//迭代显示数组元素
StringBuilder b = new StringBuilder();
b.append('[');
for (int i = 0; ; i++) {
b.append(getRaw(byteOffset(i)));
if (i == iMax)
return b.append(']').toString();
b.append(',').append(' ');
}
}