【實戰Java高併發程序設計 1】Java中的指針:Unsafe類

是《實戰Java高併發程序設計》第4章的幾點。

如果你對技術有着不折不撓的追求,應該還會特別在意incrementAndGet() 方法中compareAndSet()的實現。現在,就讓我們更進一步看一下它把!


public final boolean compareAndSet(int expect, int update){
    returnunsafe.compareAndSwapInt(this, valueOffset, expect, update);
}


在這裏,我們看到一個特殊的變量unsafe。它是sun.misc.Unsafe類型。從名字看,這個類應該是封裝了一些不安全的操作。那什麼操作是不安全的呢?學習過C或者C++的話,大家應該知道,指針是不安全的。這也是在Java中把指針去除的重要原因。如果指針指錯了位置,或者計算指針偏移量時出錯,結果可能是災難性的,你很有可能會覆蓋別人的內存,導致系統奔潰。

而這裏的Unsafe就是封裝了一些類似指針的操作。compareAndSwapInt()方法是一個navtive方法。它的幾個參數含義如下:


public final native boolean compareAndSwapInt(Object o,long offset,int expected,int x);


第一個參數o爲給定的對象,offset爲對象內的偏移量(其實就是一個字段到對象頭部的偏移量,通過這個偏移量可以快速定位字段),expected表示期望值,x表示要設置的值。如果指定的字段的值等於expected,那麼就會把它設置爲x。

不難看出,compareAndSwapInt()方法的內部,必然是使用CAS原子指令來完成的。此外,Unsafe類還提供了一些方法,主要有以下幾個(以Int操作爲例,其他數據類型是類似的):


//獲得給定對象偏移量上的int值
public native int getInt(Object o, long offset);
//設置給定對象偏移量上的int值
public native void putInt(Object o, long offset, int x);
//獲得字段在對象中的偏移量
public native long objectFieldOffset(Field f);
//設置給定對象的int值,使用volatile語義
public native void putIntVolatile(Object o, long offset,int x);
//獲得給定對象對象的int值,使用volatile語義
public native int    getIntVolatile(Object o, long offset);
//和putIntVolatile()一樣,但是它要求被操作字段就是volatile類型的
public native void putOrderedInt(Object o, long offset, intx);


如果大家還記得“3.3.4 深度剖析ConcurrentLinkedQueue”一節中的描述的ConcurrentLinkedQueue實現,應該對ConcurrentLinkedQueue中的Node還有些印象。Node一些CAS操作也都是使用Unsafe類來實現的。大家可以回顧一下,以加深對Unsafe類的印象。


這裏就可以看到,雖然Java拋棄了指針。但是在關鍵時刻,類似指針的技術還是必不可少的。這裏底層的Unsafe實現就是最好的例子。但是很不幸,JDK的開發人員並不希望大家使用這個類。獲得Unsafe實例的方法是調動其工廠方法getUnsafe()。但是,它的實現卻是這樣:


public static Unsafe getUnsafe() {
    Class cc =Reflection.getCallerClass();
    if(cc.getClassLoader() != null)
        throw newSecurityException("Unsafe");
    return theUnsafe;
}



注意加粗部分的代碼,它會檢查調用getUnsafe()函數的類,如果這個類的ClassLoader不爲null,就直接拋出異常,拒絕工作。因此,這也使得我們自己的應用程序無法直接使用Unsafe類。它是一個JDK內部使用的專屬類。

注意:根據Java 類加載器的工作原理,應用程序的類由AppLoader加載。而系統核心類,如rt.jar中的類由Bootstrap類加載器加載。Bootstrap加載器沒有Java對象的對象,因此試圖獲得這個類加載器會返回null。所以,當一個類的類加載器爲null時,說明它是由Bootstrap加載的,而這個類也極有可能是rt.jar中的類。


這本書:


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章