TIP:这是一个很危险的类,不熟悉情况下别用于生产环境
如果大家熟悉java concurrent,相信对Unsafe类不陌生。
我们知道JAVA作为高级语言的重要创新一点就是在于JVM的内存管理功能,这完全区别于C语言开发过程中需要对变量的内存分配小心控制,JVM很大程度解放了码农对于内存的调整。一直以来,JAVA在大多数人心目中没有办法对内存进行操作的,其实不然,Unsafe类就是一把操作JAVA内存的钥匙。
//不可以直接被初始化
private Unsafe() {}
//可以通过get获得实例
public static Unsafe getUnsafe() {
Class<?> caller = Reflection.getCallerClass();
if (!VM.isSystemDomainLoader(caller.getClassLoader()))
throw new SecurityException("Unsafe");
return theUnsafe;
}
在这里需要注意isSystemDomainLoader,若不设置为static final将会导致SecurityException异常
这里简单介绍几个方法:
1 类值域初始化
推荐先看一下Class初始化理解
一般类实例化的方式主要有:1.new;2.Reflect;3.ClassLoader,不同方式对应不同初始化方式
//Unsafe提供获取实例地址
public native Object allocateInstance(Class<?> cls)
throws InstantiationException;
//直接根据内存地址获取byte,Unsafe还提供了Int,Long等基本类型
//的线程安全及非线程安全取值
public native byte getByte(long address);
//同样提供了对内存数据的直接修改,并提供基本类型的线程安全及非安全
//赋值
public native void putByte(long address,byte x);
2 克隆
克隆之前经常用到两种方式:1.浅度克隆;2.深度克隆
浅度克隆实现的主要方式是clonable接口的clone方法以及通过反射获取clone对象。
深度克隆一般就比较麻烦了,需要自定义深度克隆方法。
现在我们可以操控内存,不论深度克隆亦或者浅度克隆,都只是对内存对象的操作,通过内存控制,我们很容易实现对象克隆。
//熟悉的内存分配
public native long allocateMemory(long bytes);
//熟悉的内存释放
public native void freeMemory(long address);
//内存复制,C的感觉回来了吧,浅度克隆一句搞定
//深度克隆需要考虑克隆程度,因此推荐使用WakeObject,利用反射进行克隆
public void copyMemory(long srcAddress, long destAddress, long bytes) {
560 copyMemory(null, srcAddress, null, destAddress, bytes);
561 }
3.懒加载
经常并发的数据结构中低级别的优化。
//常并发控制中,简称CAS(Compare And Swap),意思是如果valueOffset
//位置包含的值与expect值相同,则更新valueOffset位置的值为update,
//并返回true,否则不更新,返回false
public final native boolean compareAndSwapInt(Object o, long offset, int expected, int x);
//懒加载
public native void putOrderedInt(Object o, long offset, int x);
推荐看一下这篇,写的真心太好,觉得不需要再赘述JUC中Atomic class之lazySet的一点疑惑
Unsafe做操作的是直接内存区,所以该类没有办法通过HotSpot的GC进行回收,需要进行手动回收,因此在使用此类时需要注意内存泄漏(Memory Leak)和内存溢出(Out Of Memory)