关于通过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;
}
posted @ 2020-06-03 11:19  言午12138  阅读(2211)  评论(0编辑  收藏  举报