明天你会感谢今天奋力拼搏的你。
ヾ(o◕∀◕)ノヾ
sun.misc.Unsafe:在早期的JDK中,许多框架和库(如juc包中的类)依赖于sun.misc.Unsafe来实现高效的并发控制和内存操作。它提供一些低级别的操作,如直接内存访问、线程调度、CAS(Compare-And-Swap)操作等。功能强大,但也非常危险,绕过Java的安全机制,直接操作内存,容易导致崩溃或安全漏洞。然而,sun.misc.Unsafe是一个非标准API(在jdk.unsupported包下),并不是Java标准库的一部分,使用它的代码在不同的JDK版本之间可能不兼容。为了减少这种不兼容性,JDK开发者逐渐将对sun.misc.Unsafe的依赖移除或替换。
jdk.internal.misc.Unsafe:为了应对sun.misc.Unsafe的非标准化问题,JDK 9引入模块化系统(Project Jigsaw),并将一些内部API移动到jdk.internal包中。jdk.internal.misc.Unsafe是sun.misc.Unsafe的替代品,提供类似功能,但位于一个内部的、更明确的命名空间中。
两者区别
如果使用JDK9之前的版本,那么接触更多的还是sun.misc.Unsafe类。
Unsafe 类为一单例实现,提供静态方法 getUnsafe 获取 Unsafe实例。这个看上去貌似可以用来获取 Unsafe 实例。但是,当我们直接调用这个静态方法的时候,会抛出 SecurityException 异常:
Exception in thread "main" java.lang.SecurityException: Unsafe
at sun.misc.Unsafe.getUnsafe(Unsafe.java:90)
at com.cn.test.GetUnsafeTest.main(GetUnsafeTest.java:12)
为什么public static方法无法被直接调用呢?
这是因为在getUnsafe方法中,会对调用者的classLoader进行检查,判断当前类是否由Bootstrap classLoader加载,如果不是的话那么就会抛出一个SecurityException异常。也就是说,只有启动类加载器加载的类才能够调用 Unsafe 类中的方法,来防止这些方法在不可信的代码中被调用。
为什么要对 Unsafe 类进行这么谨慎的使用限制呢?
Unsafe提供的功能过于底层(如直接访问系统内存资源、自主管理内存资源等),安全隐患也比较大,使用不当的话,很容易出现很严重的问题。
如若想使用 Unsafe 这个类的话,应该如何获取其实例呢?
java -Xbootclasspath/a: ${path} // 其中path为调用Unsafe相关方法的类所在jar包路径
详细的sun.misc.unsafe类相关说明可以参考此篇文章
如果是使用JDK9(包含)之后的版本,那么就要使用jdk.internal.misc.Unsafe类。
但如下图所示,jdk.internal.misc.Unsafe类在java.base基础模块下,未对外开放,不能直接引用。
从Java9开始,Java引入了模块系统,该系统限制了模块之间的可见性和访问性。官方对使用的是Java 9或更高版本的程序,建议应该避免使用内部API,因为它们可能在未来的版本中改变或者被移除。如果确实如果你有合理的理由需要使用这个内部API,在此提供两种可以调用的方式。
(JDK模块相关知识网上很多,这里随便找了一篇文章仅供参考)
首先,针对上图编译器报红的问题,需要在编译配置如下命令:--add-exports java.base/jdk.internal.misc=ALL-UNNAMED,表示jdk.internal.misc包导出,对所有未命名模块开放。(如果你的类在你自定义的模块下面,那ALL-UNNAMED就改成你的模块名即可)
方法一:在VM Options中添加:--add-exports java.base/jdk.internal.misc=ALL-UNNAMED,即可进行直接调用。
执行如下示例代码,正常执行。
public static void main(String[] args) {
jdk.internal.misc.Unsafe unsafe = jdk.internal.misc.Unsafe.getUnsafe();
System.out.println(unsafe.addressSize());
}
方法二:VM Options中添加:--add-opens java.base/jdk.internal.misc=ALL-UNNAMED,即可通过反射获得Unsafe类的单例对象。
public static void main(String[] args) throws Exception {
// 通过反射获取Unsafe类
Class<?> unsafeClass = Class.forName("jdk.internal.misc.Unsafe");
Field field = unsafeClass.getDeclaredField("theUnsafe");
field.setAccessible(true);
Unsafe unsafe = (Unsafe) field.get(null);
System.out.println(unsafe.addressSize());
}
JDK9的Unsafe:https://blog.csdn.net/lonelymanontheway/article/details/140413151
JDK8的Unsafe:https://javaguide.cn/java/basis/unsafe.html
JDK模块:https://blog.csdn.net/weiweiqiao/article/details/142768639
全部评论