Unsafe源码解析

2022-09-18 08:47:19

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

  • 作者:雨下一整碗儿
  • 原文链接:https://blog.csdn.net/qq_41868309/article/details/116452037
    更新时间:2022-09-18 08:47:19