JDK原始碼中,在研究AQS框架時,會發現很多地方都使用了CAS操作,在併發實現中CAS操作必須具備原子性,而且是硬體級別的原子性,Java被隔離在硬體之上,明顯力不從心,這時為了能直接操作作業系統層面,肯定要通過用C++編寫的native本地方法來擴充套件實現。JDK提供了一個類來滿足CAS的要求,sun.misc.Unsafe,從名字上可以大概知道它用於執行低階別、不安全的操作,AQS就是使用此類完成硬體級別的原子操作。
Unsafe是一個很強大的類,它可以分配記憶體、釋放記憶體、可以定位物件某欄位的位置、可以修改物件的欄位值、可以使執行緒掛起、使執行緒恢復、可進行硬體級別原子的CAS操作等等,但平時我們沒有這麼特殊的需求去使用它,而且必須在受信任程式碼(一般由JVM指定)中呼叫此類,例如直接Unsafe unsafe = Unsafe.getUnsafe();獲取一個Unsafe例項是不會成功的,因為這個類的安全性很重要,設計者對其進行了如下判斷,它會檢測呼叫它的類是否由啟動類載入器Bootstrap ClassLoader(它的類載入器為null)載入,由此保證此類只能由JVM指定的類使用。
public static Unsafe getUnsafe() {
Class cc = sun.reflect.Reflection.getCallerClass(2);
if (cc.getClassLoader() != null)
throw new SecurityException("Unsafe");
return theUnsafe;
}複製程式碼
當然可以通過反射繞過上面的限制,用下面的getUnsafeInstance方法可以獲取Unsafe例項,這段程式碼演示瞭如何獲取java物件的相對地址偏移量及使用Unsafe完成CAS操作,最終輸出的是flag欄位的記憶體偏移量及CAS操作後的值。分別為8和101。另外如果使用開發工具如Eclipse,可能會編譯通不過,只要把編譯錯誤提示關掉即可。
public class UnsafeTest {
private int flag = 100;
private static long offset;
private static Unsafe unsafe = null;
static{
try{
unsafe= getUnsafeInstance();
offset= unsafe.objectFieldOffset(UnsafeTest.class
.getDeclaredField("flag"));
}catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws Exception {
int expect = 100;
int update = 101;
UnsafeTest unsafeTest = new UnsafeTest();
System.out.println("unsafeTest物件的flag欄位的地址偏移量為:"+offset);
unsafeTest.doSwap(offset,expect, update);
System.out.println("CAS操作後的flag值為:" +unsafeTest.getFlag());
}
privateboolean doSwap(long offset, int expect, int update) {
returnunsafe.compareAndSwapInt(this, offset, expect, update);
}
publicint getFlag() {
returnflag;
}
private static Unsafe getUnsafeInstance() throws SecurityException,
NoSuchFieldException,IllegalArgumentException,
IllegalAccessException{
Field theUnsafeInstance = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafeInstance.setAccessible(true);
return (Unsafe)theUnsafeInstance.get(Unsafe.class);
}
}複製程式碼
Unsafe類讓我們明白了java是如何實現對作業系統操作的,一般我們使用java是不需要在記憶體中處理java物件及記憶體地址位置的,但有的時候我們確實需要知道java物件相關的地址,於是我們使用Unsafe類,儘管java對其提供了足夠的安全管理。
Java語言的設計者們極力隱藏涉及底層作業系統的相關操作,但此節我們本著對AQS框架實現的目的,不得不剖析了Unsafe類,因為AQS裡面即是使用Unsafe獲取物件欄位的地址偏移量、相關原子操作來實現CAS操作的。
以下是廣告和相關閱讀
========廣告時間========
鄙人的新書《Tomcat核心設計剖析》已經在京東銷售了,有需要的朋友可以到 item.jd.com/12185360.ht… 進行預定。感謝各位朋友。
=========================
相關閱讀:
歡迎關注: