Unsafe -- Java的魔法类(一)
::: tip 原创不易,转载请注明来源 :::
一、简介
Unsafe,顾名思义,不安全的;Unsafe类位于sun.misc包下,执行低级、不安全操作的方法集合。对于号称是安全的编程语言Java来说,无疑它是个例外,不仅仅是因为它可以堆内存进行操作,还是通过非常规化手段获取到对象,还是对线程调度毛手毛脚,总是它不属于Java标准。因此,引得他的上司一度想干掉他(Oracle曾公开声明计划在jdk9去除Unsafe类),无奈他的势力分布太广泛,许多高性能开发库,例如Netty, Hadoop, Kafka等。Unsafe类使Java拥有了像C语言的指针一样操作内存空间的能力,同时也带来了指针的问题。过度的使用Unsafe类会使得出错的几率变大,因此Java官方并不建议使用的。但不得不提到,Unsafe类在提升Java运行效率,增强Java语言底层资源操作能力方面起到了很大的作用。
二、获取Unsafe实例
Unsafe类使用了单例模式,需要通过一个静态方法getUnsafe()进行获取。由于Unsafe类比较不安全,所以Unsafe类被创造的时候被做了些限制。普通方式进行获取实例会报java.lang.SecurityException: Unsafe异常, 原因是因为在进行获取Unsafe实例时,当且仅当调用getUnsafe方法的类为引导类加载器所加载时合法。源码如下:
public static Unsafe getUnsafe() {
Class<?> caller = Reflection.getCallerClass();
if (!VM.isSystemDomainLoader(caller.getClassLoader()))
throw new SecurityException("Unsafe");
return theUnsafe;
}
网上通常有两类方式进行获取Unsafe实例:一类是把要获取Unsafe实例的类所在jar包路径追加到默认的bootstrap路径中。另外一种则是通过反射进行获取;示例如下:
Field declaredField = Unsafe.class.getDeclaredField("theUnsafe");
declaredField.setAccessible(true);
Unsafe unsafe = (Unsafe) declaredField.get(null);
三、Unsafe的一些方法的简单介绍
1、CAS类
- java.util.concurrent.atomic相关类
- Java AQS
- CurrentHashMap
2、线程调度
- 线程挂起、恢复 park(boolean isAbsolute, long time) / unpark(Object thread)
- 获取、释放锁 monitorEnter(Object o) / monitorExit(Object o)
3、内存操作类
- 分配、拷贝、扩充、释放堆外内存
- 设置、获得给定地址中的值
4、系统相关
- 返回内存页大小
- 返回系统指针
5、数组相关
- 返回数组元素内存大小
- 返回数组首元素偏移地址
6、内存屏障
- 禁止load、store重排序
7、对象操作
- 获取对象成员属性在内存偏移量
- 非常规对象实例化
- 存储、获取指定偏移地址的变量值(包含延迟生效、volatile语义)
8、Class相关
- 动态创建类(普通类、匿名类)
- 获取field的内存地址偏移量
- 检测、确保类初始化