眾所周知,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;
}