1. 程式人生 > 實用技巧 >併發程式設計2-2 - 關於通過Unsafe.getUnsafe()方法拿Unsafe物件丟擲SecurityException異常的原因

併發程式設計2-2 - 關於通過Unsafe.getUnsafe()方法拿Unsafe物件丟擲SecurityException異常的原因

Java中的Unsafe物件可以直接呼叫記憶體,而且CAS等原子性操作中,也都是使用Unsafe物件,但當我們自己準備去使用Unsafe.getUnsafe()函式獲取Unsafe物件時,卻會丟擲SecurityException:Unsafe異常,原因是因為雙親委派制的保護機制
我們看一下Unsafe.getUnsafe()函式的原始碼:
@CallerSensitive
public static Unsafe getUnsafe() {
    // ----- 這裡去獲取當前類的ClassLoader載入器
    Class var0 = Reflection.getCallerClass();
    // ----- 判斷var0是不是BootstrapClassLoader
    if (!VM.isSystemDomainLoader(var0.getClassLoader())) {
        // ----- 否:丟擲SecurityException異常
        throw new SecurityException("Unsafe");
    } else {
        // ----- 是:返回unsafe物件
        return theUnsafe;
    }
}
Class.getClassLoader()原始碼
@CallerSensitive
public ClassLoader getClassLoader() {
    ClassLoader cl = getClassLoader0();
    if (cl == null)
        return null;
    SecurityManager sm = System.getSecurityManager();
    if (sm != null) {
        ClassLoader.checkClassLoaderPermission(cl, Reflection.getCallerClass());
    }
    return cl;
}
ClassLoader.checkClassLoaderPermission()原始碼
static void checkClassLoaderPermission(ClassLoader cl, Class<?> caller) {
    SecurityManager sm = System.getSecurityManager();
    if (sm != null) {
        // caller can be null if the VM is requesting it
        ClassLoader ccl = getClassLoader(caller);
        if (needsClassLoaderPermissionCheck(ccl, cl)) {
            sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
        }
    }
}
VM.isSystemDomainLoader()原始碼
public static boolean isSystemDomainLoader(ClassLoader var0) {
    // ----- 重點是在這裡:
    // --- 當結果為true時:說明var0是Bootstrap類載入器,
    // -- 當結果為false時:說明var0是Extension || App || Custom 等類載入器
    // ----- 所以回到getUnsafe()函式,當這個函式返回false時,會直接拋異常,不允許載入Unsafe
    return var0 == null;
}