Java魔法师Unsafe

Unsafe是位于sun.misc包下的一个类,主要提供一些用于执行低级别、不安全操作的方法,如直接访问系统内存资源、自主管理内存资源等,这些方法在提升Java运行效率、增强Java语言底层资源操作能力方面起到了很大的作用。

Unsafe的单例实现:

    @CallerSensitive
    public static Unsafe getUnsafe() {
        Class var0 = Reflection.getCallerClass();
        if (!VM.isSystemDomainLoader(var0.getClassLoader())) {
            throw new SecurityException("Unsafe");
        } else {
            return theUnsafe;
        }
    }

当且仅当调用getUnsafe方法的类为引导类加载器所加载时才合法,否则抛出SecurityException异常。

可以通过反射的方式获得theUnsafe。

try {
            Field f = Unsafe.class.getDeclaredField("theUnsafe");
            // 将字段的访问权限设置为true
            f.setAccessible(true);
            // 因为theUnsafe字段在Unsafe类中是一个静态字段,所以通过Field.get()获取字段值时,可以传null获取
            Unsafe unsafe = (Unsafe) f.get(null);

            Author author = (Author) unsafe.allocateInstance(Author.class) ;
            Field ageField = Author.class.getDeclaredField("age") ;
            long fieldOffset = unsafe.objectFieldOffset(ageField) ;

            String[] strings = new String[]{"1","2","3"} ;
            // 返回数组中第一个元素在内存中的偏移量
            long i = unsafe.arrayBaseOffset(String[].class) ;
            long address = unsafe.allocateMemory(8L) ;
            log.info("address:"+address);
        }catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }catch (InstantiationException e) {
            e.printStackTrace();
        }

Unsafe主要提供的功能如下:

  • 内存操作

典型应用:DirectByteBuffe,提供堆外内存的缓冲池,为NIO框架广泛使用。

  • CAS操作

典型应用java.util.concurrent.atomic相关类,保证原子操作,支持多线程并发

  • 线程操作

Java锁和同步器框架的核心类AbstractQueuedSynchronizer,就是通过调用LockSupport.park()和LockSupport.unpark()实现线程的阻塞和唤醒的

  • class类操作

从Java 8开始,JDK使用invokedynamic及VM Anonymous Class结合来实现Java语言层面上的Lambda表达式。

  • 对象操作

Unsafe中提供allocateInstance方法,仅通过Class对象就可以创建此类的实例对象,而且不需要调用其构造函数、初始化代码、JVM安全检查等。在Gson反序列化时,如果类有默认构造函数,则通过反射调用默认构造函数创建实例,否则通过UnsafeAllocator来实现对象实例的构造

  • 数组操作

java.util.concurrent.atomic 包下的AtomicIntegerArray(可以实现对Integer数组中每个元素的原子性操作)中有典型的应用,如下图AtomicIntegerArray源码所示,通过Unsafe的arrayBaseOffset、arrayIndexScale分别获取数组首元素的偏移地址base及单个元素大小因子scale。

  • 内存屏障

在Java 8中引入了一种锁的新机制——StampedLock,它可以看成是读写锁的一个改进版本。StampedLock提供了一种乐观读锁的实现

  • 系统相关

如下图所示的代码片段,为java.nio下的工具类Bits中计算待申请内存所需内存页数量的静态方法,其依赖于Unsafe中pageSize方法获取系统内存页大小实现后续计算逻辑。

 

更多更详细的说明以及典型使用查看美团技术写的https://www.toutiao.com/a6657827547260125700/

更多unsafe的API说明可以参考:https://blog.csdn.net/qq_34436819/article/details/102723579

你可能感兴趣的:(java)