java程式設計之:Unsafe類

無信不立發表於2016-08-27

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 }

View Code

【一】
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:  可以是一個要等待的納秒數,或者是一個相對於新紀元之後的毫秒數直到到達這個時間點


相關文章