第七節:併發程式設計之Atomic&Unsafe魔法類詳解-楊過
阿新 • • 發佈:2021-06-12
課堂筆記
說明: 併發程式設計之Atomic&Unsafe魔法類詳解
課程內容
- 什麼是原子操作?
- CPU原子操作的實現方式
- Atomic
- Unsafe魔法類
原子操作
原子即“不能被進一步分割的最小粒子”,原子操作(atomic operation)即 “ 不可被中斷的一個或一系列操作”
術語名稱 | 英文 | 解釋 |
---|---|---|
快取行 | Cache line | 快取的最小操作單位 |
比較並交換 | Compare and Swap | CAS操作需要輸入兩個數值,一箇舊值(期望操作前的值)和一個新值,在操作期間先比較下舊值有沒有發生變化,如果沒有發生變化,才交換成新值,發生了變化則不交換。 |
CPU流水線 | CPU pipeline | CPU流水線的工作方式就象工業生產上的裝配流水線,在CPU中由5-6個不同功能的電路單元組成一條指令處理流水線,然後將一條X86指令分成5~6步後再由這些電路單元分別執行,這樣就能實現在一個CPU時鐘週期完成一條指令,因此提高CPU的運算速度。 |
記憶體順序衝突 | Memory order violation | 記憶體順序衝突一般是由假共享引起,假共享是指多個CPU同時修改同一個快取行的不同部分而引起其中一個CPU的操作無效,當出現這個記憶體順序衝突時,CPU必須清空流水線。 |
處理器自動保證基本記憶體操作的原子性,如對同一個快取行裡進行16/32/64位的操作是原子的。複雜的記憶體操作處理器不能自動保證其原子性,比如跨匯流排寬度,跨多個快取行,跨頁表的訪問。
Atomic
在Atomic包裡一共有12個類,四種原子更新方式,原子更新基本型別,原子更新陣列,原子更新引用,原子更新欄位,Atomic包裡的類基本都是使用Unsafe實現的包裝類。
- 基本類: AtomicInteger、AtomicLong、AtomicBOOlean
- 引用型別:AtomicReference、AtomicReference的ABA例項、AtomicStampedReference、AtomICMarkableReference
- 陣列型別:AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray
- 屬性原子修改器(updater): AtomicIntegerFieldUpdater、AtomicLongFieldUpdater、AtomicReferenceFieldUpdater
Unsafe
Unsafe 是位於sun.misc包下的一個類,主要提供一些用於執行低級別、不安全操作的方法,如直接訪問系統記憶體資源、自主管理記憶體資源等,這些方法在提升Java執行效率、增強Java語言底層資源操作能力方面起到了很大的作用。
Unsafe類作為一單例實現,提供靜態方法getUnsafe獲取Unsafe例項,當且僅當呼叫getUnsafe方法的類為引導類載入器所載入時才合法,否則丟擲SecurityException異常。
public class Unsafe{
//單例物件
private static final Unsafe theUnsafe;
private Unsafe(){}
@CallerSensitive
public static Unsafe getUnsafe() {
Class var0 = Reflection.getCallerClass(); // 僅在引導類載入器BootstrapClassLoader 載入時才合法
if(!VM.isSystemDomainLoader(var0.getClassLoader())){
throw new SecurityException("unsafe");
}elese {
return theUnsafe;
}
}
}
如何獲取Unsafe
-
把呼叫Unsafe相關方法的類Demo所在的jar包路徑追加到預設的bootstrap路徑中,使用A被引導類載入器載入
java -Xbootclasspath/Demo:${path}
-
通過反射獲取單例物件theUnsafe
public class UnsafeInstance { public static reflectGetUnsafe() { try{ Field field = Unsafe.class.getDeclaredField("theUnsafe"); field.setAccessible(true); return (Unsafe) field.get(null); } catch (Exception e) { e.printStackTrace(); } return null; } }
Unsafe 功能
CAS
/**
* CAS
* @param o 包含要修改field的物件
* @param offset 物件中某field的偏移量
* @param expected 期望值
* @param update 更新值
* @return true | false
*/
public final native boolean compareAndSwapObject(Object var1, long var2, Object var4, Object var5);
public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);
public final native boolean compareAndSwapLong(Object var1, long var2, long var4, long var6);
執行緒排程
// 取消阻塞執行緒
public native void unpark(Object thread);
// 阻塞執行緒
public native void park(boolean isAbsolute, long time);
// 獲得物件鎖(可重入鎖)
@Deprecated
public native void monitorEnter(Object o);
//釋放物件鎖
@Deprecated
public native void monitorExit(Object o);
//嘗試獲取物件鎖
@Deprecated
public native boolean tryMonitorEnter(Object o);
記憶體屏障
//記憶體屏障,進位制load操作重排序。屏障前的load操作不能被重排序到屏障後,屏障後的load操作不能被重排序到屏障前
public native void loadFence();
//記憶體屏障,進位制store操作重排序。屏障前的store操作不能被重排序到屏障後,屏障後的store操作不能被重排序到屏障前
public native void storeFence();
//記憶體屏障,進位制load、store操作重排序
public native void fullFence()
典型應用:
StampedLock的validate()方法使用記憶體屏障,防止指令重排。
public boolean validate(long stamp){
U.loadFence();
return (stamp & SBITS) == (state && SBITS);
}