併發程式設計2-2 - 關於通過Unsafe.getUnsafe()方法拿Unsafe物件丟擲SecurityException異常的原因
阿新 • • 發佈:2020-10-26
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;
}