(1w字一篇理解透Unsafe类)Java魔法类:Unsafe详解


JUC源码中的并发工具类出现过很多次 Unsafe类,它
的功能以及使用场景这篇进行介绍。

文章导读:(约12015字,阅读时间大约1小时)

1. Unsafe介绍

Unsafe是位于sun.misc包下的类,提供一些更底层的访问系统内存资源,和管理系统内存资源的方法,但是因为会访问系统的内存资源 变成和C语言一样的指针,指针的使用是有风险的,所以Unsafe也是有类似的风险,所以在使用的时候需要注意,过度或者不正确的使用可能导致程序出错。
但是,Unsafe类也使得Java增强了底层操作系统资源的能力。
同时,Unsafe提供的功能的实现是依赖于本地方法(Native Method)的,本地方法就是Java中使用其他语言写的方法,本地方法用native修饰,java只声明方法,具体实现由本地方法实现。

使用本地方法的原因

  • 需要使用到Java没有的特性,就得使用本地方法 来用别的语言来实现,比如Java没有什么底层操作系统的能力,所以要想在跨平台的同时还可以由底层控制的能力,就要使用本地方法。
  • 其他语言已经实现的功能,可以Java调用使用
  • Java在速度上比一些更底层的语言慢,如果程序对时间要求高或者对性能要求高,那么就需要使用更底层的语言。

JUC包的很多并发工具类在实现并发功能的时候,都调用了本地方法,用来提高Java的运行上限,同时为了能更底层的操作操作系统,也会使用本地方法,对于本地方法来说,不同操作系统的实现不太一样,但是使用起来是一样的。

2. Unsafe创建

public final class Unsafe {
   
  // 单例对象
  private static final Unsafe theUnsafe;
  ......
  private Unsafe() {
   
  }
  @CallerSensitive
  public static Unsafe getUnsafe() {
   
    Class var0 = Reflection.getCallerClass();
    // 仅在引导类加载器`BootstrapClassLoader`加载时才合法
    if(!VM.isSystemDomainLoader(var0.getClassLoader())) {
   
      throw new SecurityException("Unsafe");
    } else {
   
      return theUnsafe;
    }
  }
}

Unsafe类是单例实现,可以通过静态getUnsafe方法获取实例。但是有个前提是 在调用getUnsafe方法的时候会对调用者的ClassLoader进行检查,也就是检查类加载器,如果是由Bootstrap classLoader加载的,那么才可以获得实例 如果不是那么就抛出异常SecurityException,所以,只有启动类加载器加载的类才可以调用Unsafe类中的方法,有助于避免被不可信代码调用,(因为这个原因说一在获取Unsafe类的实例的时候 大概率会抛出SecurityException异常,这样就要有别的方法来获取实例,比如下面讲到的反射方法)

那么为什么使用Unsafe类这么有限制?
Unsafe类提供的功能很底层,它可以访问系统资源,操作系统资源,所以存在一些安全风险,

在这个限制的条件下如何来获取Unsafe实例呢
我知道的方法是一个:
通过反射
我们可以通过反射来获得Unsafe类中以及完成实例化的theUnsafe对象

//通过反射获取Unsafe类中已经实例化完成的theUnsafe对象
    private static Unsafe reflectGetUnsafe() {
   
        try {
   
            Field field = Unsafe.class.getDeclaredField("theUnsafe");
            field.setAccessible(true);
            return (Unsafe) field.get(null);
        } catch (NoSuchFieldException e) {
   //处理异常
            e.printStackTrace();
            return null;//返回内容
        } catch (IllegalAccessException e) {
   
            e.printStackTrace();
            return null;
        }
    }

3. Unsafe功能

3.1内存操作

Java中不能直接操作内存,对象的分配内存和释放都是JVM完成的,在Unsafe中,提供了几个方法可以直接操作内存:

//分配新的本地空间
public native long allocateMemory(long bytes);
//重新调整内存空间的大小
public native long reallocateMemory(long address, long bytes);
//将内存设置为指定值
public native void setMemory(Object o, long offset, long bytes, byte value);
//内存拷贝
public native void copyMemory(Object srcBase, long srcOffset,Object destBase, long destOffset,long bytes);
//清除内存
public native void freeMemory(long address);

测试:

 public void  Test() {
   
        Unsafe unsafe = reflectGetUnsafe();
        int size = 4;
        long addr = unsafe.allocateMemory(size);
        long addr1 = unsafe.reallocateMemory(addr,size*2);
        System.out.println("addr:" + addr);
        System.out.println("addr1:" + addr1);
        try {
   
            unsafe.setMemory(null,addr,size,(
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

keild

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值