并发编程学习笔记(二十八、Unsafe)
目录:
- 什么是Unsafe、为什么要有Unsafe
- Unsafe源码简述
什么是Unsafe、为什么要有Unsafe
我们知道Java和C、C++这种语言最大的差别就是Java不能直接操作内存,而C、C++可以;但其实在某些场景下我们为了进一步提升效率我们不得不直接操作内存。
而Unsafe就提供了内存操作及一些其它的特性,他们都是native方法,由JVM实现。一般来说日常的开发是用不到的,但是JUC源码中你可以随手看到。
——————————————————————————————————————————————————————————————————————
Unsafe核心功能如下:
- 普通读写、volatile读写、有序写
- 直接内存操作
- CAS操作
- 偏移量相关
- 线程调度
- 类加载
- 内存屏障
- 等等等等
Unsafe源码简述
在前面我们说到了Unsafe的七大核心功能,现在我们来看下Unsafe分别为这些功能提供了哪些操作吧。
读写:
1、普通读写
1 public native int getInt(Object var1, long var2); 2 public native void putInt(Object var1, long var2, int var4);
传入一个对象,在其偏移量上读取一个int,或是写入一个int;当然其它基本类型也有类似的方法,如getBoolean、putBoolean、getDouble、putDouble等等。
不仅如此,Unsafe还提供了直接在一个地址上读写:
1 public native byte getByte(Object var1, long var2); 2 public native void putByte(Object var1, long var2, byte var4);
——————————————————————————————————————————————————————————————————————
2、volatile读写
普通的读写无法保证有序性和可见性,所以Unsafe还提供了volatile读写,同样的也提供了基本类型与地址读写。
1 public native void putObjectVolatile(Object var1, long var2, Object var4); 2 public native int getIntVolatile(Object var1, long var2); 3 // ......
3、有序写
对于普通读写来说volatile读写过于昂贵了,因为并不是所有场景你都是需要保证可见性的,所以Unsafe还提供了只保证有序性的写;
它含盖的方法与普通读写、volatile读写不同,只提供了int、long、object三个类型的写入。
1 public native void putOrderedObject(Object var1, long var2, Object var4); 2 public native void putOrderedInt(Object var1, long var2, int var4); 3 public native void putOrderedLong(Object var1, long var2, long var4);
直接内存操作:
1 /** 分配内存 **/ 2 public native long allocateMemory(long var1); 3 /** 重新分配内存 **/ 4 public native long reallocateMemory(long var1, long var3); 5 /** 初始化内存 **/ 6 public native void setMemory(Object var1, long var2, long var4, byte var6); 7 /** 内存复制 **/ 8 public native void copyMemory(Object var1, long var2, Object var4, long var5, long var7); 9 /** 清除内存 **/ 10 public native void freeMemory(long var1);
CAS操作:
1 public final native boolean compareAndSwapObject(Object var1, long var2, Object var4, Object var5); 2 public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5); 3 public final native boolean compareAndSwapLong(Object var1, long var2, long var4, long var6);
偏移量相关:
1 /** 获取静态属性在对象中的偏移量,读写静态属性时必须获取其偏移量 **/ 2 public native long staticFieldOffset(Field var1); 3 /** 获取非静态属性在对象中的偏移量,读写非静态属性时会用到这个偏移量 **/ 4 public native long objectFieldOffset(Field var1); 5 /** 返回Field所在的对象 **/ 6 public native Object staticFieldBase(Field var1); 7 /** 返回数组中第一个元素实际地址相对整个数组的地址偏移量 **/ 8 public native int arrayBaseOffset(Class<?> var1); 9 /** 计算数组中第一个元素所占用的内存空间 **/ 10 public native int arrayIndexScale(Class<?> var1);
线程调度:
1 /** 唤醒线程 **/ 2 public native void unpark(Object var1); 3 /** 挂起线程 **/ 4 public native void park(boolean var1, long var2); 5 6 @Deprecated 7 public native void monitorEnter(Object var1); 8 @Deprecated 9 public native void monitorExit(Object var1); 10 @Deprecated 11 public native boolean tryMonitorEnter(Object var1);
monitorEnter、monitorExit用于加锁,Java中synchronize锁就是通过这两个指令来实现的。
类加载:
1 /** 定义一个类,用于动态地创建类 **/ 2 public native Class<?> defineClass(String var1, byte[] var2, int var3, int var4, ClassLoader var5, ProtectionDomain var6); 3 /** 动态的创建一个匿名内部类 **/ 4 public native Class<?> defineAnonymousClass(Class<?> var1, byte[] var2, Object[] var3); 5 /** 创建一个类的实例,但不会调用这个实例的构造方法,若未被初始化则初始化这个类 **/ 6 public native Object allocateInstance(Class<?> var1) throws InstantiationException; 7 /** 判断是否需要初始化一个类 **/ 8 public native boolean shouldBeInitialized(Class<?> var1); 9 /** 用于保证已经初始化过一个类 **/ 10 public native void ensureClassInitialized(Class<?> var1);
内存屏障:
1 /** 保证在这个屏障之前的所有读操作都已经完成 **/ 2 public native void loadFence(); 3 /** 保证在这个屏障之前的所有写操作都已经完成 **/ 4 public native void storeFence(); 5 /** 保证在这个屏障之前的所有读写操作都已经完成 **/ 6 public native void fullFence();
——————————————————————————————————————————————————————————————————————