Unsafe類在jdk 源碼的多個類中用到,這個類的提供了一些繞開JVM的更底層功能,基於它的實現可以提高效率。但是,它是一把雙刃劍:正如它的名字所預示的那樣,它是 Unsafe的,它所分配的內存需要手動free(不被GC回收)。Unsafe類,提供了JNI某些功能的簡單替代:確保高效性的同時,使事情變得更簡 單。
這篇文章主要是以下文章的整理、翻譯。
http://mishadoff.com/blog/java-magic-part-4-sun-dot-misc-dot-unsafe/
1. Unsafe API的大部分方法都是native實現,它由105個方法組成,主要包括以下幾類:
(1)Info相關。主要返回某些低級別的內存信息:addressSize(), pageSize()
(2)Objects相關。主要提供Object和它的域操縱方法:allocateInstance(),objectFieldOffset()
(3)Class相關。主要提供Class和它的靜態域操縱方法:staticFieldOffset(),defineClass(),defineAnonymousClass(),ensureClassInitialized()
(4)Arrays相關。數組操縱方法:arrayBaseOffset(),arrayIndexScale()
(5)Synchronization相關。主要提供低級別同步原語(如基於CPU的CAS(Compare-And-Swap)原 語):monitorEnter(),tryMonitorEnter(),monitorExit(),compareAndSwapInt(),putOrderedInt()
(6)Memory相關。直接內存訪問方法(繞過JVM堆直接操縱本地內存):allocateMemory(),copyMemory(),freeMemory(),getAddress(),getInt(),putInt()

1 package com.yeepay.sxf.hashmaptest; 2 3 import java.lang.reflect.Field; 4 5 import sun.misc.Unsafe; 6 7 public class TestUnSafe { 8 9 public static void main(String[] args) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException, InstantiationException { 10 //獲取屬性 11 Field f=Unsafe.class.getDeclaredField("theUnsafe"); 12 // 13 f.setAccessible(true); 14 //獲取實例 15 Unsafe unsafe=(Unsafe) f.get(null); 16 17 //實例化一個類 18 Player player=(Player) unsafe.allocateInstance(Player.class); 19 //打印年齡 打印結果:0 20 System.out.println("TestUnSafe.enclosing_method()"+player.getAge()); 21 22 player.setAge(100); 23 24 //打印結果100 25 System.out.println("TestUnSafe.main()"+player.getAge()); 26 27 } 28 29 } 30 31 /** 32 * 普通類 33 * @author sxf 34 * 35 */ 36 class Player{ 37 //年齡 38 private int age=12; 39 40 //構造函數私有化 41 private Player(){ 42 this.age=50; 43 } 44 45 public int getAge() { 46 return age; 47 } 48 49 public void setAge(int age) { 50 this.age = age; 51 } 52 }
【一】
public native long objectFieldOffset(Field field);
==> 返回指定靜態field的內存地址偏移量,在這個類的其他方法中這個值只是被用作一個訪問
==>特定field的一個方式。這個值對於 給定的field是唯一的,並且后續對該方法的調用都應該返回相同的值
【二】
public native boolean compareAndSwapInt(Object obj, long offset, int expect, int update);
==>在obj的offset位置比較long field和期望的值,如果相同則更新。這個方法的操作應該是原子的,因此提供了一種不可中斷的方式更新long field。成功返回true,不成功返回false
==>obj:包含要修改field的對象
==>offset:obj對象中long型field的偏移量
==>expect:希望field中存在的值
==>update:如果期望值expect與field的當前值相同,設置filed的值為這個新值
【三】
public native boolean compareAndSwapObject(Object obj, long offset, Object expect, Object update);
==>在obj的offset位置比較object field和期望的值,如果相同則更新。這個方法的操作應該是原子的,因此提供了一種不可中斷的方式更新object field.成功返回true,不成功返回false
==>obj:包含要修改field的對象
==>offset:obj中object型field的偏移量
==>expect:希望field中存在的值
==>update:如果期望值expect與field的當前值相同,設置filed的值為這個新值
【四】
public native void putOrderedInt(Object obj, long offset, int value);
==>設置obj對象中offset偏移地址對應的整型field的值為指定值。這是一個有序或者有延遲的putIntVolatile方法,並且不保證值的改變被其他線程立即看到。只有在field被<code>volatile</code>修飾並且期望被意外修改的時候使用才有用。
==>obj: 包含要修改field的對象
==>offset: <code>obj</code>中整型field的偏移量
==>value: field將被設置的新值
【五】
public native void putOrderedLong(Object obj, long offset, long value);
==>設置obj對象中offset偏移地址對應的long型field的值為指定值。這是一個有序或者有延遲的<code>putLongVolatile</cdoe>方法,並且不保證值的改變被其他線程立即看到。只有在field被<code>volatile</code>修飾並且期望被意外修改的時候使用才有用。
==>obj:包含需要修改field的對象
==>offset:<code>obj</code>中long型field的偏移量
==>value:field將被設置的新值
【六】
public native void putOrderedObject(Object obj, long offset, Object value);
==>設置obj對象中offset偏移地址對應的整型field的值為指定值。支持volatile store語義
==>obj:包含需要修改field的對象
==>offset:<code>obj</code>中整型field的偏移量
==>value:field將被設置的新值
【七】
public native void putIntVolatile(Object obj, long offset, int value);
==>設置obj對象中offset偏移地址對應的整型field的值為指定值。支持volatile store語義
==>obj: 包含需要修改field的對象
==>offset:<code>obj</code>中整型field的偏移量
==>value:field將被設置的新值
【八】
public native int getIntVolatile(Object obj, long offset);
==>獲取obj對象中offset偏移地址對應的整型field的值,支持volatile load語義。
==>obj: 包含需要去讀取的field的對象
==>offset:<code>obj</code>中整型field的偏移量
【九】
public native void putLongVolatile(Object obj, long offset, long value);
==>設置obj對象中offset偏移地址對應的long型field的值為指定值。
==>obj:包含需要修改field的對象
==>offset: <code>obj</code>中long型field的偏移量
==>value: field將被設置的新值
【十】
public native long getLongVolatile(Object obj, long offset);
==>獲取obj對象中offset偏移地址對應的long型field的值,支持volatile load語義。
==> obj:包含需要去讀取的field的對象
==>offset:<code>obj</code>中long型field的偏移量
【十一】
public native void putLong(Object obj, long offset, long value);
==>設置obj對象中offset偏移地址對應的long型field的值為指定值。
==>obj:包含需要修改field的對象
==>offset: <code>obj</code>中long型field的偏移量
==>value:field將被設置的新值
【十二】
public native long getLong(Object obj, long offset);
==> 獲取obj對象中offset偏移地址對應的long型field的值
==>obj:包含需要去讀取的field的對象
==>offset:<code>obj</code>中long型field的偏移量
【十三】
public native void putObjectVolatile(Object obj, long offset, Object value);
==> 設置obj對象中offset偏移地址對應的object型field的值為指定值。
==>obj:包含需要修改field的對象
==>offset:<code>obj</code>中object型field的偏移量
==>value:field將被設置的新值
【十四】
public native Object getObjectVolatile(Object obj, long offset);
==>獲取obj對象中offset偏移地址對應的object型field的值,支持volatile load語義。
==>obj:包含需要去讀取的field的對象
==>offset: <code>obj</code>中object型field的偏移量
【十五】
public native int arrayBaseOffset(Class arrayClass);
==>獲取給定數組中第一個元素的偏移地址。 為了存取數組中的元素,這個偏移地址與<a href="#arrayIndexScale"><code>arrayIndexScale* </code></a>方法的非0返回值一起被使用
==>arrayClass:第一個元素地址被獲取的class
==>返回:數組第一個元素 的偏移地址
【十六】
public native int arrayIndexScale(Class arrayClass);
==>獲取用戶給定數組尋址的換算因子.一個合適的換算因子不能返回的時候(例如:基本類型), 返回0.這個返回值能夠與<a href="#arrayBaseOffset"><code>arrayBaseOffset</code> </a>一起使用去存取這個數組class中的元素
【十七】
public native void unpark(Thread thread);
==>釋放被<a href="#park"><code>park</code></a>創建的在一個線程上的阻塞.這個方法也可以被使用來終止一個先前調用<code>park</code>導致的阻塞.這個操作操作時不安全的,因此線程必須保證是活的.這是java代碼不是native代碼
==>thread: 要解除阻塞的線程
【十八】
public native void park(boolean isAbsolute, long time);
==>阻塞一個線程直到<a href="#unpark"><code>unpark</code></a>出現、線程被中斷或者timeout時間到期。如果一個<code>unpark</code>調用已經出現了,這里只計數。timeout為0表示永不過期.當<code>isAbsolute</code>為true時,timeout是相對於新紀元之后的毫秒。否則這個值就是超時前的納秒數。這個方法執行時也可能不合理地返回(沒有具體原因)
==>isAbsolute:如果為true timeout的值是一個相對於新紀元之后的毫秒數
==>time: 可以是一個要等待的納秒數,或者是一個相對於新紀元之后的毫秒數直到到達這個時間點