什么是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源码前要知识

无参构造方法:private Unsafe() {}

Unsafe类的内部常量:private static final Unsafe theUnsafe = new Unsafe();

我们每次获取的就是一个单例对象,我们通过getXXX取得内部私有变量即可。

如何获取Unsafe对象

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)

@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对象

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);
}
控制台输出
sun.misc.Unsafe@6ae40994

通过Unsafe类绕过JVM到对象管理机制 实现方法调用。

白话就是:不new,不反射,执行目标类中public的方法!

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(); // 执行对象方法
    }
}
Singleton printDIY

进程已结束,退出代码0

案例中没有打印无参构造方法,说明我们通过反射获取的Unsafe,可以绕过常规的类加载机制,在不new的前提,调用目标类的方法

一个非常牛逼的国外作者关于Unsafe的文章:http://mishadoff.com/blog/java-magic-part-4-sun-dot-misc-dot-unsafe/

  1. 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()

特殊说明:
上述文章均是作者实际操作后产出。烦请各位,请勿直接盗用!转载记得标注原文链接:www.zanglikun.com
第三方平台不会及时更新本文最新内容。如果发现本文资料不全,可访问本人的Java博客搜索:标题关键字。以获取全部资料 ❤