最近为了更加深入了解NIO的实现原理,学习NIO的源码时,遇到了一个问题。即在WindowsSelectorImpl中的
pollWrapper属性,当我点进去查看它的PollArrayWrapper类型时,发现它和AllocatedNativeObject类型有关,而AllocatedNativeObject继承了NativeObject类,随着又发现了NativeObject是基于一个Unsafe类实现的。不安全的类????
Unsafe
Unsafe,顾名思义,它真是一个不安全的类,那它为什么是不安全的呢?这就要从Unsafe类的功能说起。
学过C#的就可以知道,C#和Java的一个重要区别就是:C#可以直接操作一块内存区域,如自己申请内存和释放,而在Java中这是做不到的。而Unsafe类就可以让我们在Java中像C#一样去直接操作一块内存区域,正因为Unsafe类可以直接操作内存,意味着其速度更快,在高并发的条件之下能够很好地提高效率,所以java中很多并发框架,如Netty,都使用了Unsafe类。
虽然,Unsafe可以提高运行速度,但是因为Java本身是不支持自己直接操作内存的,这就意味着Unsafe类所做的操作不受jvm管理的,所以不会被GC(垃圾回收),需要我们手动GC,稍有不慎就会出现内存泄漏问题。且Unsafe的不少方法中必须提供原始地址(内存地址)和被替换对象的地址,偏移量要自己计算,一旦出现问题就是JVM崩溃级别的异常,会导致整个JVM实例崩溃。这就是为什么Unsafe被称为不安全的原因。Unsafe可以让你全力踩油门,提高自己的速度,但是它会让你的方向盘更难握稳,一不小心就可能导致车毁人亡。
源码查看初始化
因为Unsafe的构造方法是private类型的,所以无法通过new方式实例化获取,只能通过它的getUnsafe()方法获取。又因为Unsafe是直接操作内存的,为了安全起见,Java的开发人员为Unsafe的获取设置了限制,所以想要获取它只能通过Java的反射机制来获取。
@CallerSensitive public static Unsafe getUnsafe() { //通过getCallerClass方法获取Unsafe类 Class var0 = Reflection.getCallerClass(); //如过该var0类不是启动类加载器(Bootstrap),则抛出异常 //正因为该判断,所以Unsafe只能通过反射获取 if (!VM.isSystemDomainLoader(var0.getClassLoader())) { throw new SecurityException("Unsafe"); } else { return theUnsafe; } }