Unsafe
介绍:
Java无法直接访问底层操作系统,而是通过本地方法(native)来访问。Java中的Unsafe类为我们提供了管理内存的能力。
创建Unsafe对象
Unsafe类是final的,不允许继承,而且构造函数是私有的,无法通过new的方式创建对象:
publicfinalclassUnsafe{// 构造函数私有privateUnsafe(){}...}
但是我们可以通过反射的方式获取Unsafe对象:
staticvoidtestUnsafe()throws NoSuchFieldException, IllegalAccessException{
Class<?> unsafeClass= Unsafe.class;
Field theUnsafe= unsafeClass.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
Unsafe unsafe=(Unsafe) theUnsafe.get(unsafeClass);
System.out.println(unsafe);}
Unsafe的主要功能
1,普通读写
可以通过Unsafe去读写一个类的属性,不管这个类是否私有(直接从内存读写)。
// var1: 要读的对象 var2: 对象的偏移地址publicnativeintgetInt(Object var1,long var2);// var1: 要读的对象 var2: 对象的偏移地址 var3: 新写入的数据publicnativevoidputInt(Object var1,long var2,int var4);
getInt() 方法用于从对象的指定偏移地址处读取一个int类型的数据,需要指定要读取的对象和偏移量。
putInt() 方法用于在对象的指定地址出写入一个int类型的数据,需要执行要读取的对象、偏移量和新写入的值。其他类型的数据也有相同的方法,如Object和Boolean:
// 对象publicnative ObjectgetObject(Object var1,long var2);publicnativevoidputObject(Object var1,long var2, Object var4);// 布尔publicnativebooleangetBoolean(Object var1,long var2);publicnativevoidputBoolean(Object var1,long var2,boolean var4);
2,Volatile读写
1步骤中的读写是普通的读写操作,无法保证可见性和有序性。而源码中相应的volatile方法就可保证有序性和可见性:
// volatile读publicnativeintgetIntVolatile(Object var1,long var2);// volatile写publicnativevoidputIntVolatile(Object var1,long var2,int var4);
getIntVolatile方法的作用是在对象的指定位置volatile读一个int类型数据,putIntVolatile是在指定位置volatile写一个数据(volatile解析详见 02-关键字volatile解析)。
3,有序写入
有序写入只保证写入的有序性,并不保证可见性,也就是说,该线程的写入不保证其他线程能立马看到。Unsafe类中,只提供了三种类型的有序写方法:
publicnativevoidputOrderedObject(Object var1,long var2, Object var4);publicnativevoidputOrderedInt(Object var1,long var2,int var4);publicnativevoidputOrderedLong(Object var1,long var2,long var4);
4,CAS操作
CAS: Compare And Swap。Unsafe中提供了三种类型Object、int、long的CAS操作。
publicfinalnativebooleancompareAndSwapObject(Object var1,long var2, Object var4, Object var5);publicfinalnativebooleancompareAndSwapInt(Object var1,long var2,int var4,int var5);publicfinalnativebooleancompareAndSwapLong(Object var1,long var2,long var4,long var6);
java.util.concurrent中的一些类用到了大量的CAS操作,如AtomicInteger等原子类的写操作和ConcurrentHashMap等类的乐观锁。
5,获取偏移量
我们可以通过偏移量和对象得到对象中属性在内存中所处的位置。Unsafe提供了如下方式:
// 获取静态属性Field在对象中的偏移量publicnativelongstaticFieldOffset(Field var1);// 获取非静态属性在对象中的偏移量publicnativelongobjectFieldOffset(Field var1);// 返回Field所在对象publicnative ObjectstaticFieldBase(Field var1);// 返回数组中第一个元素的偏移量publicnativeintarrayBaseOffset(Class<?> var1);// 返回数组中第一个元素所占用的内存空间publicnativeintarrayIndexScale(Class<?> var1);
6,线程调度
publicnativevoidunpark(Object var1);publicnativevoidpark(boolean var1,long var2);
Unsafe中的park()和unpark()方法实现了对线程的挂起和唤醒。LockSupport中的park()和unpark()方法就是依靠Unsafe中的这两个方法实现的:
// 线程挂起publicstaticvoidpark(Object blocker){
Thread t= Thread.currentThread();setBlocker(t, blocker);
UNSAFE.park(false,0L);// 挂起setBlocker(t, null);}// 线程唤醒publicstaticvoidunpark(Thread thread){if(thread!= null)
UNSAFE.unpark(thread);}
7,直接内存操作
在学习JVM时,我们知道Java不可以直接堆内存进行操作,对象内存的分配、回收都是Java虚拟机实现的。Unsafe中提供了直接操作内存的能力。
// 分配内存publicnativelongallocateMemory(long var1);// 重新分配内存publicnativelongreallocateMemory(long var1,long var3);// 设置内存publicnativevoidsetMemory(Object var1,long var2,long var4,byte var6);// 设置内存publicvoidsetMemory(long var1,long var3,byte var5){this.setMemory((Object)null, var1, var3, var5);}// 复制publicnativevoidcopyMemory(Object var1,long var2, Object var4,long var5,long var7);// 复制publicvoidcopyMemory(long var1,long var3,long var5){this.copyMemory((Object)null, var1,(Object)null, var3, var5);}// 清除内存publicnativevoidfreeMemory(long var1);
8,类加载
// 定义一个类,用于动态创建类publicnative Class<?>defineClass(String var1,byte[] var2,int var3,int var4, ClassLoader var5, ProtectionDomain var6);// 用于动态创建一个匿名内部类publicnative Class<?>defineAnonymousClass(Class<?> var1,byte[] var2, Object[] var3);// 用于创建一个类的实例,但是不会调用这个实例的构造方法,如果这个类还未被初始化,则初始化这个类publicnative ObjectallocateInstance(Class<?> var1)throws InstantiationException;// 判断是否需要初始化一个类publicnativebooleanshouldBeInitialized(Class<?> var1);// 保证一个类已经被初始化publicnativevoidensureClassInitialized(Class<?> var1);
9,内存屏障
// 保证这个屏障之前所有读操作已经完成publicnativevoidloadFence();// 保证这个屏障之前所有写操作已经完成publicnativevoidstoreFence();// 保证这个屏障之前所有读写操作都完成publicnativevoidfullFence();
参考博客:https://www.jianshu.com/p/db8dce09232d