AQS 架構之 Unsafe 源碼詳解,aqsunsafe

來源:互聯網
上載者:User

AQS 架構之 Unsafe 源碼詳解,aqsunsafe

■ 前言

  之前 LockSupport 那篇已經敘述了是線程阻塞工具類,其底層由 Unsafe 實現,即 park(), unpark() 方法,擷取指標位移量,並操縱記憶體。本篇主要介紹 Unsafe 的源碼,看看底層到底做了什麼。

 

■ Unsafe 綜述

  • 作用: Unsafe是個後門類,封裝了一些類似指標的操作,提供了一些可以直接操控記憶體和線程的底層操作
  • 使用: Unsafe被JDK廣泛用於nio包和並發包中,但是不建議在生產環境使用,風險太大
  • 不安全: 不安全指的是指標的操作不安全(Java因此才把指標去掉),若指標指錯位置或計算指標位移量出錯,結果不可想象,比如說覆蓋了別人的記憶體,那可能就GG思密達了...
  • 補充1: 有機會開JVM番的話,筆者會從JVM源碼角度重新解析Unsafe一些重要方法的實現
  • 補充2: 此番為 AQS 架構之綜述 (趕製中) 的子番

 

■ Unsafe 資料結構

 1. 類定義

public final class Unsafe

   2. 構造器

//私人構造器 --單例模式private Unsafe() {}

  3. 重要變數

private static final Unsafe theUnsafe;public static final int INVALID_FIELD_OFFSET = -1;public static final int ARRAY_BOOLEAN_BASE_OFFSET;public static final int ARRAY_BYTE_BASE_OFFSET;public static final int ARRAY_SHORT_BASE_OFFSET;public static final int ARRAY_CHAR_BASE_OFFSET;public static final int ARRAY_INT_BASE_OFFSET;public static final int ARRAY_LONG_BASE_OFFSET;public static final int ARRAY_FLOAT_BASE_OFFSET;public static final int ARRAY_DOUBLE_BASE_OFFSET;public static final int ARRAY_OBJECT_BASE_OFFSET;public static final int ARRAY_BOOLEAN_INDEX_SCALE;public static final int ARRAY_BYTE_INDEX_SCALE;public static final int ARRAY_SHORT_INDEX_SCALE;public static final int ARRAY_CHAR_INDEX_SCALE;public static final int ARRAY_INT_INDEX_SCALE;public static final int ARRAY_LONG_INDEX_SCALE;public static final int ARRAY_FLOAT_INDEX_SCALE;public static final int ARRAY_DOUBLE_INDEX_SCALE;public static final int ARRAY_OBJECT_INDEX_SCALE;public static final int ADDRESS_SIZE;private static native void registerNatives();static {    registerNatives();    Reflection.registerMethodsToFilter(Unsafe.class, new String[]{"getUnsafe"});    theUnsafe = new Unsafe();//單例模式 -餓漢式    ARRAY_BOOLEAN_BASE_OFFSET = theUnsafe.arrayBaseOffset(boolean[].class);    ARRAY_BYTE_BASE_OFFSET = theUnsafe.arrayBaseOffset(byte[].class);    ARRAY_SHORT_BASE_OFFSET = theUnsafe.arrayBaseOffset(short[].class);    ARRAY_CHAR_BASE_OFFSET = theUnsafe.arrayBaseOffset(char[].class);    ARRAY_INT_BASE_OFFSET = theUnsafe.arrayBaseOffset(int[].class);    ARRAY_LONG_BASE_OFFSET = theUnsafe.arrayBaseOffset(long[].class);    ARRAY_FLOAT_BASE_OFFSET = theUnsafe.arrayBaseOffset(float[].class);    ARRAY_DOUBLE_BASE_OFFSET = theUnsafe.arrayBaseOffset(double[].class);    ARRAY_OBJECT_BASE_OFFSET = theUnsafe.arrayBaseOffset(Object[].class);    ARRAY_BOOLEAN_INDEX_SCALE = theUnsafe.arrayIndexScale(boolean[].class);    ARRAY_BYTE_INDEX_SCALE = theUnsafe.arrayIndexScale(byte[].class);    ARRAY_SHORT_INDEX_SCALE = theUnsafe.arrayIndexScale(short[].class);    ARRAY_CHAR_INDEX_SCALE = theUnsafe.arrayIndexScale(char[].class);    ARRAY_INT_INDEX_SCALE = theUnsafe.arrayIndexScale(int[].class);    ARRAY_LONG_INDEX_SCALE = theUnsafe.arrayIndexScale(long[].class);    ARRAY_FLOAT_INDEX_SCALE = theUnsafe.arrayIndexScale(float[].class);    ARRAY_DOUBLE_INDEX_SCALE = theUnsafe.arrayIndexScale(double[].class);    ARRAY_OBJECT_INDEX_SCALE = theUnsafe.arrayIndexScale(Object[].class);    ADDRESS_SIZE = theUnsafe.addressSize();}

  4. 重要方法

//獲得給定對象記憶體位移量的int值public native int getInt(Object var1, long var2);//設定給定對象記憶體位移量的int值public native void putInt(Object var1, long var2, int var4);public native Object getObject(Object var1, long var2);public native void putObject(Object var1, long var2, Object var4);//....還有Boolean、Byte、Char、Short、Long、Float、Double的get\set....//記憶體配置、釋放//分配記憶體public native long allocateMemory(long var1);//擴充記憶體public native long reallocateMemory(long var1, long var3);public native void setMemory(Object var1, long var2, long var4, byte var6);public void setMemory(long var1, long var3, byte var5) {    this.setMemory((Object)null, var1, var3, var5);}//拷貝記憶體public native void copyMemory(Object var1, long var2, Object var4, long var5, long var7);public void copyMemory(long var1, long var3, long var5) {    this.copyMemory((Object)null, var1, (Object)null, var3, var5);}//釋放記憶體public native void freeMemory(long var1);//擷取欄位在對象中的記憶體位移量public native long staticFieldOffset(Field var1);public native long objectFieldOffset(Field var1);public native Object staticFieldBase(Field var1);public native void ensureClassInitialized(Class<?> var1);//數組元素定位//arrayBaseOffset 和 arrayIndexScale 搭配使用可以定位元組中每個元素在記憶體中的位置//擷取數組第一個元素的位移地址public native int arrayBaseOffset(Class<?> var1);//擷取數組的轉換因子,也就是數組中元素的增量地址public native int arrayIndexScale(Class<?> var1);public native int addressSize();public native int pageSize();//類定義public native Class<?> defineClass(String var1, byte[] var2, int var3, int var4, ClassLoader var5, ProtectionDomain var6);public native Class<?> defineClass(String var1, byte[] var2, int var3, int var4);public native Class<?> defineAnonymousClass(Class<?> var1, byte[] var2, Object[] var3);//建立執行個體public native Object allocateInstance(Class<?> var1) throws InstantiationException;//Synchronized同步塊的指令實現 1.8版的全部是@Deprecatedpublic native void monitorEnter(Object var1);public native void monitorExit(Object var1);public native boolean tryMonitorEnter(Object var1);//異常拋出public native void throwException(Throwable var1);//CAS操作/*** 比較obj的offset處記憶體位置中的值和期望的值,如果相同則更新,此更新是不可中斷的* @param obj 需要更新的對象* @param offset obj中整型field的位移量* @param expect 希望field中存在的值* @param update 如果期望值expect與field的當前值相同,設定filed的值為這個新值* @return 如果field的值被更改返回true*/public final native boolean compareAndSwapObject(Object obj, long offset, Object expect, Object update);public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);public final native boolean compareAndSwapLong(Object var1, long var2, long var4, long var6);//擷取給定對象的指定類型值,支援volatile load語義public native Object getObjectVolatile(Object var1, long var2);public native void putObjectVolatile(Object var1, long var2, Object var4);public native int getIntVolatile(Object var1, long var2);//設定給定對象的int值,支援volatile load語義public native void putIntVolatile(Object var1, long var2, int var4);//....還有Boolean、Byte、Char、Short、Long、Float、Double的volatile層級的get\put....public native void putDoubleVolatile(Object var1, long var2, double var4);public native void putOrderedObject(Object var1, long var2, Object var4);public native void putOrderedInt(Object var1, long var2, int var4);public native void putOrderedLong(Object var1, long var2, long var4);//LockSupport類的原語支援-掛起和喚醒某個線程public native void unpark(Object var1);public native void park(boolean var1, long var2);public native int getLoadAverage(double[] var1, int var2);//提供安全執行緒的add和set操作public final int getAndAddInt(Object var1, long var2, int var4) {int var5;    do {        var5 = this.getIntVolatile(var1, var2);    } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));    return var5;}public final int getAndSetInt(Object var1, long var2, int var4) {    int var5;    do {        var5 = this.getIntVolatile(var1, var2);    } while(!this.compareAndSwapInt(var1, var2, var5, var4));    return var5;}//...還有Long和Object的安全執行緒的add和set操作...//柵欄支援public native void loadFence();public native void storeFence();public native void fullFence();

  5. 禁用的Factory 方法

@CallerSensitivepublic static Unsafe getUnsafe() {    Class var0 = Reflection.getCallerClass();    //該方法用於判斷調用者的類載入器是否是系統核心載入器(即Bootstrap載入器)    if(!VM.isSystemDomainLoader(var0.getClassLoader())) {        throw new SecurityException("Unsafe");    } else {        return theUnsafe;    }}
  • 我們先顯性調用該Factory 方法查看一下調用結果
package concurrent;import sun.misc.Unsafe;public class UnsafeDemo {    public static void main(String[] args) {        Unsafe.getUnsafe();    }}-------------------//輸出:Exception in thread "main" java.lang.SecurityException: Unsafe    at sun.misc.Unsafe.getUnsafe(Unsafe.java:90)    at concurrent.UnsafeDemo.main(UnsafeDemo.java:7)//分析:可以發現直接調用的話會直接拋出安全異常,原因是類載入器是AppClassLoader而並非是BootstrapLoader  

 

  • 根據Java 類載入器的工作原理,應用程式的類由AppLoader載入,而系統核心類由BootstrapLoader載入
  • 當一個類的類載入器為null時,說明它是由BootstrapLoader載入的,即此類是系統核心類(比如rt.jar包中的類)
  • 當一個類無法被BootstrapLoader載入時,其類載入器通常為AppClassLoader,即是屬於自訂類

 

■ Unsafe 反射擷取

/**   * 我們可以通過反射機制擷取Unsafe 的一個執行個體  */public static Unsafe getUnsafe(){    try {        //通過反射擷取Unsafe的theUnsafe變數,即Unsafe執行個體對象        Field f = Unsafe.class.getDeclaredField("theUnsafe");        f.setAccessible(true);        //注意field是static屬性        //參見:private static final Unsafe theUnsafe;        return (Unsafe) f.get(null);    } catch (Exception e) {        e.printStackTrace();    }    return null;}

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.