以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;
}