1.2.2 執行緒安全之原子操作
阿新 • • 發佈:2019-12-31
競態條件與臨界區
共享資源
不可變物件
原子操作定義
- 原子操作可以是一個步驟,也可以是多個操作步驟,但是其順序不可以被打亂,也不可以被切割而只執行其中的一部分(不可中斷性)。
- 將整個操作視作一個整體,資源在該次操作中保持一致,這是原子性的核心特徵。
CAS機制
volatile int value = 0;
static Unsafe unsafe; // 直接操作記憶體,修改物件,陣列記憶體....強大的API
private static long valueOffset;
static {
try {
// 反射技術獲取unsafe值
Field field = Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
unsafe = (Unsafe) field.get(null);
// 獲取到 value 屬性偏移量(用於定於value屬性在記憶體中的具體地址)
valueOffset = unsafe.objectFieldOffset(LockDemo1.class
.getDeclaredField("value" ));
} catch (Exception ex) {
ex.printStackTrace();
}
}
public void add() {
// TODO xx00
// i++;// JAVA 層面三個步驟
// CAS + 迴圈 重試
int current;
do {
// 操作耗時的話, 那麼 執行緒就會佔用大量的CPU執行時間
current = unsafe.getIntVolatile(this ,valueOffset);
} while (!unsafe.compareAndSwapInt(this,valueOffset,current,current + 1));
// (可能會失敗)CAS命令,如果current值發生變化,則操作失敗
}
複製程式碼
- 有興趣的童鞋可以瞭解下Unsafe的原始碼,類似於直接操作記憶體的方法。JVM呼叫系統本地方法操作資料,保證只有一個執行緒可以訪問到本地方法操作,實現原子操作。
J.U.C包內的原子操作封裝類
- java.until.concurrent執行緒工具類(J.U.C)
CAS的三個問題
- JAVA提供了ABA的解決辦法:原子更新帶有版本號的引用型別。CAS在比對是不僅比對值,還會比對版本號。
- Atomic原子操作封裝類,將i++分成了幾步(讀取值,更新值,賦值),使用了底層的CAS機制,並且不僅僅存了值,還存了時間戳版本號。