並發之AtomicIntegerArray
阿新 • • 發佈:2018-05-18
IT atom ini ont ring uid 理解 class ger 5 並發之AtomicIntegerArray
該類是Java對Integer數組支持的原子性操作;在認識這個類之前我們先來看一個方法,這個方法是Integer類中的;
public static int numberOfLeadingZeros(int i) {}
看看官方的解釋吧:返回具有至多單個 1 位的 int 值,在指定的 int 值中最高位(最左邊)的 1 位的位置。
看完官方的解釋大家知道了吧;哈哈,說實話其實我也沒能理解;但是這並不妨礙我們對該方法的使用;
該方法直譯過來就是抵達0位置的個數:
先來看一段代碼吧:
在這裏我需要做一個補充說明;看如下的代碼所示(是AutomicIntegerArray中的方法):
public class IntegerArrayTest {
public static void main(String[] args) {
Integer a=1;
Integer b=13;
Integer c=25;
/**
* 0000 0000 0000 0000 0000 0000 0000 0000
* 0000 0000 0000 0000 0000 0000 0000 0001 0的個數為31 1
* 0000 0000 0000 0000 0000 0000 0000 1101 0的個數為28 13
* 0000 0000 0000 0000 0000 0000 0001 1001 0的個數為27 25
* a的二進制為=1 最左邊開始數起連續0的個數為31
* b的二進制為=1101 最左邊開始數起連續0的個數為28
* c的二進制為=11001 最左邊開始數起連續0的個數為27
*/
System.out.println("a的二進制為="+Integer.toBinaryString(a)+" 最左邊開始數起連續0的個數為"+Integer.numberOfLeadingZeros(a));
System.out.println("b的二進制為="+Integer.toBinaryString(b)+" 最左邊開始數起連續0的個數為"+Integer.numberOfLeadingZeros(b));
System.out.println("c的二進制為="+Integer.toBinaryString(c)+" 最左邊開始數起連續0的個數為"+Integer.numberOfLeadingZeros(c));
}
}
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 {
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);
}
}
在看上述的代碼之前,我先來說一個問題: 在AutomicInteger類中,value的值是使用了volatile修飾的;會對所有的線程立即可見;但是本身又不可以保證原子性的操作;那麽為什麽還要在該類中使用這個關鍵字呢?
在這裏我需要做一個補充說明;看如下的代碼所示(是AutomicIntegerArray中的方法):
1 /**
2 * 原子性的設置一個值
3 */
4 public final void set(int i, int newValue) {
5 unsafe.putIntVolatile(array, checkedByteOffset(i), newValue);
6 }
下面的源碼是AutomicInteger類中的set()方法
/**
* 原子性的設置一個值
*/
public final void set(int newValue) {
value = newValue;
}
大家看到了吧,兩個方法的本質是一樣的,第一個方法使用了CAS算法,並且獲原子性的設置了這個數組中元素的值;之所以使用volatile是對其它線程立馬可見;這個才是最重要的原因;而對於lazySet()方法而言,是沒有使用volatile關鍵字的;因為它對其他線程是屬於賴設置的;也就是不能馬上被其他線程可見;也就是說可以變量共享,但是使用了volatile將失去JVM的優化作用;原子性操作我認為大多數操作或者讀的操作沒有使用volatile的關鍵是讀可以多線程共享,寫不是共享的;其實CAS算法設計的就是樂觀鎖的思想;
public static void automicIntegerArray() {
/**
* 創建一個原子性的數組,長度為5
*/
AtomicIntegerArray atomicArray = new AtomicIntegerArray(5);
/**
* 設置第一個元素的值為5
*/
atomicArray.set(0, 5);
/**
* 第一個元素減去1
*/
int current = atomicArray.decrementAndGet(0);
System.out.println("current = " + current);//current = 4
}
看AutomicIntegerArray的構造器
/**
* 創建一個原子性整※數組,並且長度為length;而且初始值都為0
* elements initially zero.
*/
public AtomicIntegerArray(int length) {
array = new int[length];
}
並發之AtomicIntegerArray