1. 程式人生 > 其它 >第七節:併發程式設計之Atomic&Unsafe魔法類詳解-楊過

第七節:併發程式設計之Atomic&Unsafe魔法類詳解-楊過

課堂筆記

說明: 併發程式設計之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

  1. 把呼叫Unsafe相關方法的類Demo所在的jar包路徑追加到預設的bootstrap路徑中,使用A被引導類載入器載入

    • java -Xbootclasspath/Demo:${path}
  2. 通過反射獲取單例物件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);
}