多執行緒(五): CAS無鎖機制
java程式設計規範中long與double操作並不是原子的,在java的部分執行環境中,對於long以及double的操作並不是原子的。
例如有一個long型別的longfield欄位,某個執行緒正在執行:longfield = 123L ;這樣的指定操作,而同時有另一個執行緒正在執行:longfield = 456L;這樣的指定操作。之後longfield的值會是什麼,是無法保證的。也許是123L,也可能是456L,或許是0L,甚至還可能是31415926L。
所以我們可以的出下列結論:
1.基本型別,引用型別的指定,引用是原子的操作;
2.但是long與double的指定,引用是分割的;
3.要線上程間共享long與double欄位是,必須在synchronized中操作,或是宣告為volatile。
以前只知道Java中的long與double不是執行緒安全的,但不知道為什麼,讀《深入java虛擬機器》一書,瞭解了大概。
Java虛擬機器規範定義的許多規則中的一條:所有對基本型別的操作,除了某些對long型別和double型別的操作之外,都必須是原子級的。
由於規範沒有規定如何實現,那麼當今所知的虛擬機器對這條規則的實現都是把32位值做為原子性對待,而不是64位做為原子性。那麼,當執行緒把主存中的long/double型別的值讀到執行緒記憶體中時,可能是兩次32位值的寫操作,顯而易見,如果幾個執行緒同時操作,那麼就可能會出現高低2個32位值出錯的情況發生,所以現在,java程式必須確保通過同步來操作共享的long和double。
AtomicInteger:原子數字
可以對int型進行自增、自減、相加操作,保證操作的原子性。
原子類有AtomicLong、AtomicBoolean、AtomicReference等
public class AtomicInteger extends Number implements java.io.Serializable {
private static final long serialVersionUID = 6214790243416807050L;
// 獲取指標類Unsafe
private static final Unsafe unsafe = Unsafe.getUnsafe();
//下述變數value在AtomicInteger例項物件內的記憶體偏移量
private static final long valueOffset;
static {
try {
//通過unsafe類的objectFieldOffset()方法,獲取value變數在物件記憶體中的偏移
//通過該偏移量valueOffset,unsafe類的內部方法可以獲取到變數value對其進行取值或賦值操作
valueOffset = unsafe.objectFieldOffset
(AtomicInteger.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
}
//當前AtomicInteger封裝的int變數value
private volatile int value;
public AtomicInteger(int initialValue) {
value = initialValue;
}
public AtomicInteger() {
}
//獲取當前最新值,
public final int get() {
return value;
}
//設定當前值,具備volatile效果,方法用final修飾是為了更進一步的保證執行緒安全。
public final void set(int newValue) {
value = newValue;
}
//最終會設定成newValue,使用該方法後可能導致其他執行緒在之後的一小段時間內可以獲取到舊值,有點類似於延遲載入
public final void lazySet(int newValue) {
unsafe.putOrderedInt(this, valueOffset, newValue);
}
//設定新值並獲取舊值,底層呼叫的是CAS操作即unsafe.compareAndSwapInt()方法
public final int getAndSet(int newValue) {
return unsafe.getAndSetInt(this, valueOffset, newValue);
}
//如果當前值為expect,則設定為update(當前值指的是value變數),更新成功返回true,失敗返回false
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
//當前值加1返回舊值,底層CAS操作
public final int getAndIncrement() {
return unsafe.getAndAddInt(this, valueOffset, 1);
}
//當前值減1,返回舊值,底層CAS操作
public final int getAndDecrement() {
return unsafe.getAndAddInt(this, valueOffset, -1);
}
//當前值增加delta,返回舊值,底層CAS操作
public final int getAndAdd(int delta) {
return unsafe.getAndAddInt(this, valueOffset, delta);
}
//當前值加1,返回新值,底層CAS操作
public final int incrementAndGet() {
return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}
//當前值減1,返回新值,底層CAS操作
public final int decrementAndGet() {
return unsafe.getAndAddInt(this, valueOffset, -1) - 1;
}
//當前值增加delta,返回新值,底層CAS操作
public final int addAndGet(int delta) {
return unsafe.getAndAddInt(this, valueOffset, delta) + delta;
}
}
public class AtomicIntegerTest {
public static void main(String[] args) {
AtomicInteger atomicInteger = new AtomicInteger(10);
int newValue = atomicInteger.incrementAndGet();
// 11
System.out.println(newValue);
boolean flag = atomicInteger.compareAndSet(10, 100);
int currentValue = atomicInteger.get();
// false 11
System.out.println(flag + "\t" + currentValue);
int newValue2 = atomicInteger.incrementAndGet();
// 12
System.out.println(newValue2);
int newValue3 = atomicInteger.decrementAndGet();
// 11
System.out.println(newValue3);
int newValue4 = atomicInteger.addAndGet(10);
// 21
System.out.println(newValue4);
}
}