什么是Unsafe类?
Unsafe封装了很多底层基础的操作,比如:数组操作、对象操作、内存操作、CAS操作、线程(park)操作、栅栏(Fence)操作,JUC包
Unsafe类在JDK 8中归属于sun.misc包下,其他JDK版本包位置会略有不同,不过官方期望在后续删除Unsafe类,不建议我们去用。sun下面都所有包都可能会涉及到C 底层操作。
Unsafe作用
官话作用:可用来直接访问系统内存资源并进行自主管理。
实质作用:绕开JVM的实现更底层功能。Unsafe类在提升Java运行效率,增强Java语言底层操作能力方面起了很大的作用。
基于Unsafe诞生了很多高性能框架
Unsafe可认为是Java中留下的后门,提供了一些低层次操作,如直接内存访问、线程调度等。得益于这些操作,一些高性能框架基于此:比如Netty、Cassandra、Hadoop、Kafka等。
Unsafe源码前要知识
代码语言:javascript复制无参构造方法:private Unsafe() {}
Unsafe类的内部常量:private static final Unsafe theUnsafe = new Unsafe();
我们每次获取的就是一个单例对象,我们通过getXXX取得内部私有变量即可。
如何获取Unsafe对象
代码语言:javascript复制public static void main(String[] args) {
Unsafe willError = Unsafe.getUnsafe(); // 这是我们常见的获取Unsafe方法。但是他会报错
}
我们看一下报错以及原因
Exception in thread “main” java.lang.SecurityException: Unsafe at sun.misc.Unsafe.getUnsafe(Unsafe.java:90) at com.zanglikun.springdataredisdemo.XX.main(XX.java:16)
代码语言:javascript复制@CallerSensitive
public static Unsafe getUnsafe() {
Class<?> caller = Reflection.getCallerClass();
if (!VM.isSystemDomainLoader(caller.getClassLoader()))
throw new SecurityException("Unsafe");
return theUnsafe;
}
很明显,上文getUnsafe()方法 if中内容,是判定是否是系统去调用这个方法,如果不是就会跑出SecurityException,所以我们就无法正常创建Unsafe对象了。我们获取一个对象,要么new,要么反射。所以,我们需要反射获取Unsafe对象
代码语言:javascript复制public static void main(String[] args) throws NoSuchFieldException {
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
Unsafe unsafe = (Unsafe) theUnsafe.get(null);
System.out.println(unsafe);
}
代码语言:javascript复制控制台输出
sun.misc.Unsafe@6ae40994
通过Unsafe类绕过JVM到对象管理机制 实现方法调用。
白话就是:不new,不反射,执行目标类中public的方法!
代码语言:javascript复制import sun.misc.Unsafe;
import java.lang.reflect.Field;
class Singleton {
// 注意无参构造方法是private的,也就是说我们无法常规new这个对象!
private Singleton() {
System.out.println("Singleton 无参构造 示例化对象,如果我没打印,就代表我不是常规new 出来的对象");
}
public void printDIY() {
System.out.println("Singleton printDIY");
}
}
public class UserVO {
public static void main(String[] args) throws Exception {
Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
unsafeField.setAccessible(true);
Unsafe unsafe = (Unsafe) unsafeField.get(null); // 获取Unsafe对象
Singleton singleton = (Singleton) unsafe.allocateInstance(Singleton.class); // 获取对象示例
singleton.printDIY(); // 执行对象方法
}
}
代码语言:javascript复制Singleton printDIY
进程已结束,退出代码0
案例中没有打印无参构造方法,说明我们通过反射获取的Unsafe,可以绕过常规的类加载机制,在不new的前提,调用目标类的方法。
一个非常牛逼的国外作者关于Unsafe的文章:http://mishadoff.com/blog/java-magic-part-4-sun-dot-misc-dot-unsafe/
- Unsafe API的大部分方法都是native实现,它由105个方法组成,主要包括以下几类:
(1)Info相关。主要返回某些低级别的内存信息:addressSize(), pageSize()
(2)Objects相关。主要提供Object和它的域操纵方法:allocateInstance(),objectFieldOffset()
(3)Class相关。主要提供Class和它的静态域操纵方法:staticFieldOffset(),defineClass(),defineAnonymousClass(),ensureClassInitialized()
(4)Arrays相关。数组操纵方法:arrayBaseOffset(),arrayIndexScale()
(5)Synchronization相关。主要提供低级别同步原语(如基于CPU的CAS(Compare-And-Swap)原语):monitorEnter(),tryMonitorEnter(),monitorExit(),compareAndSwapInt(),putOrderedInt()
(6)Memory相关。直接内存访问方法(绕过JVM堆直接操纵本地内存):allocateMemory(),copyMemory(),freeMemory(),getAddress(),getInt(),putInt()
特殊说明: 以上文章,均是我实际操作,写出来的笔记资料,不会盗用别人文章!烦请各位,请勿直接盗用!转载记得标注来源!