1. 程式人生 > >Java 1.8 Unsafe

Java 1.8 Unsafe

name ssl misc sun ini malloc absolut lean 操作

Unsafe 類在 sun.misc 包下,不屬於Java標準。但是很多 Java 的基礎類庫,以及優秀的三方庫都會用這個提升性能。

Unsafe 使用了單例模式,想使用 Unsafe 類就需要獲取實例。由於安全限制,不能用一般的方法獲取這個實例,通常都是使用反射獲取

public class UnsafeDemo {
    static sun.misc.Unsafe U;
    
    static {
        try {
            Field f = Unsafe.class.getDeclaredField("theUnsafe");
            f.setAccessible(
true); U = (Unsafe) f.get(null); } catch (Exception e) { throw new Error(e); } } }

Unsafe 類幾類功能:

內存管理

long allocateMemory(long bytes)

  向操作系統申請一塊本地內存,大小為 bytes 字節,返回內存塊的地址。本地內存是指不由 JVM 管理的內存,不會被 GC 管理。

  底層使用 malloc 實現

long reallocateMemory(long address, long bytes)

  resize 一塊本地內存,address 是原內存地址, bytes 是新大小。

  如果 address 是 0,則內部用 allocateMemory 分配新內存;如果 bytes 是 0,則用 freeMemory 釋放原內存。

  底層使用 realloc 實現。

void freeMemory(long address)

  釋放由 allocateMemory 申請的內存

  底層用 free 實現

int pageSize()

  返回一頁內存的大小

int addressSize()

  返回一個指針的大小

內存操作

內存操作需要提供地址。UnSafe 需要地址的場合會需要兩個參數 Object o, long offset

  如果 o 是 null, offset 將被視為具體的內存地址;

  如果 o 非 null,offset 被為字段在對象或數組中的偏移。 o 和 offset 一起得到一個有效地址

void setMemory(Object o, long offset, long bytes, byte value)

  將一塊內存設置為固定值。

void setMemory(long address, long bytes, byte value)

  等價於 setMemory(null, address, bytes, value);

void copyMemory(Object srcBase, long srcOffset, Object destBase, long destOffset, long bytes)

  復制內存

void copyMemory(long srcAddress, long destAddress, long bytes)

  等價於 copyMemory(null, srcAddress, null, destAddress, bytes)

put / get 系列

T getT(Object o, long offset)

void putT(Object o, long offset, T x)

  T 可以是 int、boolean、byte、short、char、long、float、double

  另外還有不需要 Object o 參數的版本,等價於 getT(null, address)

Object getObject(Object o, long offset)

void putObject(Object o, long offset, Object x)

T getTVolatile(Object o, long offset)

void putTVolatile(Object o, long offset, T x)

  帶 volatile 語義的 put / get

long getAddress(Object o, long offset)

  從指定地址獲取一個內存指針

void putAddress(Object o, long offset, long x)

  將指針存到指定地址

void putOrderedObject(Object o, long offset, Object x)

void putOrderedInt(Object o, long offset, int x)

void putOrderedLong(Object o, long offset, long x)

  保證寫後立即可見

計算類字段內存位置

long staticFieldOffset(Field f)

  返回一個靜態字段的內存位置

long objectFieldOffset(Field f)

  返回一個指定字段的存儲位置

Object staticFieldBase(Field f)

  返回一個靜態字段的存儲位置,是一個引用

非常規的對象實例化

Object allocateInstance(Class<?> cls)

  創建一個類實例,但不執行構造方法

數組操作

int arrayBaseOffset(Class<?> arrayClass)

  返回 arrayClass 類型數組的第 0 個元素到數組對象內存開始的偏移

int arrayIndexScale(Class<?> arrayClass)

  返回一個數組元素需要的長度大小

異常

void throwException(Throwable ee)

  該方法拋出受檢異常,但代碼不必捕捉或重新拋出它,正如運行時異常一樣

動態類

Class<?> defineClass(String name, byte[] b, int off, int len, ClassLoader loader, ProtectionDomain protectionDomain)

  從字節碼創建一個類

Class<?> defineAnonymousClass(Class<?> hostClass, byte[] data, Object[] cpPatches)

  從字節碼創建匿名類

void ensureClassInitialized(Class<?> c)

  加載類

boolean shouldBeInitialized(Class<?> c)

  檢查類是否已加載

多線程同步

void monitorEnter(Object obj)

  鎖定對象

void monitorExit(Object obj)

  釋放鎖

monitorEnter 和 monitorExit 的組合相當於 synchronized 關鍵字

boolean tryMonitorEnter(Object obj)

  嘗試鎖定對象

以上 3 個都是 @Deprecated 的方法

原子操作

boolean compareAndSwapObject(Object o, long offset, Object expected, Object x)

boolean compareAndSwapInt(Object o, long offset, int expected, int x)

boolean compareAndSwapLong(Object o, long offset, long expected, long x)

  如果變量的值是 expected,則更新成 x,原子更新

int getAndAddInt(Object o, long offset, int delta)

long getAndAddLong(Object o, long offset, long delta)

  原子加

getAndSetInt(Object o, long offset, int newValue)

getAndSetLong(Object o, long offset, long newValue)

getAndSetObject(Object o, long offset, Object newValue)

  原子地設置新值和返回舊值

掛起與恢復

void park(boolean isAbsolute, long time)

  暫停當前線程

void unpark(Object thread)

  通知線程恢復

JDK concurrent 包的鎖大部分用這個實現

內存屏障

void loadFence()

  在該方法之前的所有讀操作,一定在load屏障之前執行完成

void storeFence()

  在該方法之前的所有寫操作,一定在store屏障之前執行完成

void fullFence()

  在該方法之前的所有讀寫操作,一定在full屏障之前執行完成,這個內存屏障相當於上面兩個的合體功能

Java 1.8 Unsafe