Unsafe原子性

LZC發表於2020-08-07

JDK的rt.jar包中的Unsafe類提供了硬體級別的原子性操作,Unsafe類中的方法都是native方法,它們使用JNI的方式訪問本地C++ 實現庫。下面我們來了解一下Unsafe提供的幾個主要的方法以及程式設計時如何使用Unsafe類做一些事情。

  • long objectFieldOffset(Field field)方法:返回指定的變數在所屬類中的記憶體偏移地址,該偏移地址僅僅在該Unsafe函式中訪問指定欄位時使用。
  • boolean compareAndSwapLong(Object obj, longoffset, long expect, long update)方法:比較物件obj中偏移量為offset的變數的值是否與expect相等,相等則使用update值更新,然後返回true,否則返回false。
  • public native long getLongvolatile(Object obj, longoffset)方法:獲取物件obj中偏移量為offset的變數對應volatile語義的值。
  • void putLongvolatile(Object obj, long offset, longvalue)方法:設定obj物件中offset偏移的型別為long的field的值為value,支援volatile語義。
public class UnsafeTest {
    //獲得Unsafe的一個例項
    static final Unsafe unsafe;
    static final long stateOffset;
    private volatile long state = 0;

    static {
        try {
            // 使用反射獲取Unsafe的成員變數theUnsafe
            Field field = Unsafe.class.getDeclaredField("theUnsafe");
            // 設定為可存取
            field.setAccessible(true);
            // 獲取該變數的值
            unsafe = (Unsafe) field.get(null);
            // 獲取 UnsafeTest 類裡面的 state 變數, 在 UnsafeTest 物件裡面的記憶體偏移量地址並將其儲存到 stateOffset 變數中。
            // getDeclaredFields():獲得某個類的所有宣告的欄位
            stateOffset = unsafe.objectFieldOffset(UnsafeTest.class.getDeclaredField("state"));
        } catch (Exception e) {
            System.out.println(e.getLocalizedMessage());
            throw new Error(e);
        }
    }
    public static void main(String[] args){
        UnsafeTest unsafeTest = new UnsafeTest();
        // 如果 unsafeTest 物件中 記憶體偏移量為 stateOffset 的 state 變數的值為 0,則更新該值為 1
        boolean b = unsafe.compareAndSwapLong(unsafeTest, stateOffset, 0, 1);
        System.out.println(b);//true
        System.out.println(unsafeTest.state);
    }
}
本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章