Java并发学习(四)-sun.misc.Unsafe
来源:互联网 发布:道路照度计算软件 编辑:程序博客网 时间:2024/06/05 10:39
Unsafe
Unsafe类是什么呢?java不能直接访问操作系统底层,而是通过本地方法来访问。Unsafe类提供了硬件级别的原子操作。或许在读源码时候会发现,LockSupport里面会调用到unsafe.park,undafe.unpark,而同样在AQS里面会调用到unsafe里面众多CAS相关代码。
这些天在看源码时候,总会遇到park,unpark,CAS相关指令,都是从Unsafe里面调用,所以就花了点时间整体的阅读了Unsafe的源码,注释了所有方法,里面方法基本是native,这篇文章没有去深究相关方法c++实现,我的其他博文会有相关方法的深究~
概念
字段的定位:
JAVA中对象的字段的定位可能通过staticFieldOffset方法实现,该方法返回给定field的内存地址偏移量,这个值对于给定的filed是唯一的且是固定不变的。
- getIntVolatile方法获取对象中offset偏移地址对应的整型field的值,volatile方式获取int值
- getLong方法获取对象中offset偏移地址对应的long型field的值
数组元素定位:
Unsafe类中有很多以BASE_OFFSET结尾的常量,比如ARRAY_INT_BASE_OFFSET,ARRAY_BYTE_BASE_OFFSET等,这些常量值是通过arrayBaseOffset方法得到的。arrayBaseOffset方法是一个本地方法,可以获取数组第一个元素的偏移地址。Unsafe类中还有很多以INDEX_SCALE结尾的常量,比如 ARRAY_INT_INDEX_SCALE , ARRAY_BYTE_INDEX_SCALE等,这些常量值是通过arrayIndexScale方法得到的。arrayIndexScale方法也是一个本地方法,可以获取数组的转换因子,也就是数组中元素的增量地址。将arrayBaseOffset与arrayIndexScale配合使用,可以定位数组中每个元素在内存中的位置。
源码
Unsafe源代码地址:http://hg.openjdk.java.net/jdk8u/jdk8u/jdk/file/07011844584f/src/share/classes/sun/misc/Unsafe.java
下面看带注释的代码:
/** * * @author John R. Rose * @see #getUnsafe * * 用getUnsafe来获取unsafe实例。 * 大部分方法是底层级的,直接对应着硬件的指令。 */public final class Unsafe { private static native void registerNatives(); static { registerNatives(); sun.reflect.Reflection.registerMethodsToFilter(Unsafe.class, "getUnsafe"); } private Unsafe() { } //final类型,保证会被正确初始化 private static final Unsafe theUnsafe = new Unsafe(); //获取unsafe实例的操作。 @CallerSensitive public static Unsafe getUnsafe() { Class<?> caller = Reflection.getCallerClass(); //判断caller的类加载器是否为系统类加载器。 if (!VM.isSystemDomainLoader(caller.getClassLoader())) throw new SecurityException("Unsafe"); return theUnsafe; } // 以下是一些读内存和写内存的操作。主要是从Java堆中。 //并且以下方法不会作用与数组和引用。 // 获取o的偏移地址为offset的int值。 public native int getInt(Object o, long offset); //在o的偏移地址为offset处存储x。 public native void putInt(Object o, long offset, int x); //获取o的偏移地址为offset的Object类型的引用的值。 public native Object getObject(Object o, long offset); //下面方法同上 public native void putObject(Object o, long offset, Object x); /** @see #getInt(Object, long) */ public native boolean getBoolean(Object o, long offset); /** @see #putInt(Object, int, int) */ public native void putBoolean(Object o, long offset, boolean x); /** @see #getInt(Object, long) */ public native byte getByte(Object o, long offset); /** @see #putInt(Object, int, int) */ public native void putByte(Object o, long offset, byte x); /** @see #getInt(Object, long) */ public native short getShort(Object o, long offset); /** @see #putInt(Object, int, int) */ public native void putShort(Object o, long offset, short x); /** @see #getInt(Object, long) */ public native char getChar(Object o, long offset); /** @see #putInt(Object, int, int) */ public native void putChar(Object o, long offset, char x); /** @see #getInt(Object, long) */ public native long getLong(Object o, long offset); /** @see #putInt(Object, int, int) */ public native void putLong(Object o, long offset, long x); /** @see #getInt(Object, long) */ public native float getFloat(Object o, long offset); /** @see #putInt(Object, int, int) */ public native void putFloat(Object o, long offset, float x); /** @see #getInt(Object, long) */ public native double getDouble(Object o, long offset); /** @see #putInt(Object, int, int) */ public native void putDouble(Object o, long offset, double x); // 以下主要在c语言堆上分配内存相关操作。 //从特定内存地址里面获得byte值,没有则为undefined public native byte getByte(long address); //把byte x的值放入到address处内存地址。 public native void putByte(long address, byte x); /** @see #getByte(long) */ public native short getShort(long address); /** @see #putByte(long, byte) */ public native void putShort(long address, short x); /** @see #getByte(long) */ public native char getChar(long address); /** @see #putByte(long, byte) */ public native void putChar(long address, char x); /** @see #getByte(long) */ public native int getInt(long address); /** @see #putByte(long, byte) */ public native void putInt(long address, int x); /** @see #getByte(long) */ public native long getLong(long address); /** @see #putByte(long, byte) */ public native void putLong(long address, long x); /** @see #getByte(long) */ public native float getFloat(long address); /** @see #putByte(long, byte) */ public native void putFloat(long address, float x); /** @see #getByte(long) */ public native double getDouble(long address); /** @see #putByte(long, byte) */ public native void putDouble(long address, double x); //从已经给的一个内存地址中获取本地指针地址。 public native long getAddress(long address); //把一个本地指针值x存储到内存地址address处。 public native void putAddress(long address, long x); // 内存分配函方法,malloc,free等 //分配一个bytes大小的内存块,返回内存地址。 public native long allocateMemory(long bytes); //为内存地址为address的空间重新分配大小为bytes的地址。 public native long reallocateMemory(long address, long bytes); //把o的偏移地址为offset的值处内存,分配bytes大小内存空间,并设值为value。 public native void setMemory(Object o, long offset, long bytes, byte value); //把绝对地址为offset的值处内存,分配bytes大小内存空间,并设值为value public void setMemory(long address, long bytes, byte value) { setMemory(null, address, bytes, value); } //将源object的srcoffset偏移地址处的bytes大小内存,放入destBase偏移地址 public native void copyMemory(Object srcBase, long srcOffset, Object destBase, long destOffset, long bytes); //同上,绝对地址上设置。 public void copyMemory(long srcAddress, long destAddress, long bytes) { copyMemory(null, srcAddress, null, destAddress, bytes); } //释放地址为address初的内存。 public native void freeMemory(long address); // / random queries,随机查询。 //错误地址 public static final int INVALID_FIELD_OFFSET = -1; //获取静态变量f的内存地址 public native long staticFieldOffset(Field f); //获取普通变量f的内存地址。 public native long objectFieldOffset(Field f); //获取静态变量f的内存地址。 public native Object staticFieldBase(Field f); //检测,当前class c是否应该被初始化, public native boolean shouldBeInitialized(Class<?> c); //保证当前class c 已经被初始化了。 public native void ensureClassInitialized(Class<?> c); //返回arrayClass类第一个字节的地址。 public native int arrayBaseOffset(Class<?> arrayClass); /** The value of {@code arrayBaseOffset(boolean[].class)} */ public static final int ARRAY_BOOLEAN_BASE_OFFSET = theUnsafe .arrayBaseOffset(boolean[].class); /** The value of {@code arrayBaseOffset(byte[].class)} */ public static final int ARRAY_BYTE_BASE_OFFSET = theUnsafe .arrayBaseOffset(byte[].class); /** The value of {@code arrayBaseOffset(short[].class)} */ public static final int ARRAY_SHORT_BASE_OFFSET = theUnsafe .arrayBaseOffset(short[].class); /** The value of {@code arrayBaseOffset(char[].class)} */ public static final int ARRAY_CHAR_BASE_OFFSET = theUnsafe .arrayBaseOffset(char[].class); /** The value of {@code arrayBaseOffset(int[].class)} */ public static final int ARRAY_INT_BASE_OFFSET = theUnsafe .arrayBaseOffset(int[].class); /** The value of {@code arrayBaseOffset(long[].class)} */ public static final int ARRAY_LONG_BASE_OFFSET = theUnsafe .arrayBaseOffset(long[].class); /** The value of {@code arrayBaseOffset(float[].class)} */ public static final int ARRAY_FLOAT_BASE_OFFSET = theUnsafe .arrayBaseOffset(float[].class); /** The value of {@code arrayBaseOffset(double[].class)} */ public static final int ARRAY_DOUBLE_BASE_OFFSET = theUnsafe .arrayBaseOffset(double[].class); /** The value of {@code arrayBaseOffset(Object[].class)} */ public static final int ARRAY_OBJECT_BASE_OFFSET = theUnsafe .arrayBaseOffset(Object[].class); //返回数组元素的大小,注意byte类型获取则为0 public native int arrayIndexScale(Class<?> arrayClass); /** The value of {@code arrayIndexScale(boolean[].class)} */ public static final int ARRAY_BOOLEAN_INDEX_SCALE = theUnsafe .arrayIndexScale(boolean[].class); /** The value of {@code arrayIndexScale(byte[].class)} */ public static final int ARRAY_BYTE_INDEX_SCALE = theUnsafe .arrayIndexScale(byte[].class); /** The value of {@code arrayIndexScale(short[].class)} */ public static final int ARRAY_SHORT_INDEX_SCALE = theUnsafe .arrayIndexScale(short[].class); /** The value of {@code arrayIndexScale(char[].class)} */ public static final int ARRAY_CHAR_INDEX_SCALE = theUnsafe .arrayIndexScale(char[].class); /** The value of {@code arrayIndexScale(int[].class)} */ public static final int ARRAY_INT_INDEX_SCALE = theUnsafe .arrayIndexScale(int[].class); /** The value of {@code arrayIndexScale(long[].class)} */ public static final int ARRAY_LONG_INDEX_SCALE = theUnsafe .arrayIndexScale(long[].class); /** The value of {@code arrayIndexScale(float[].class)} */ public static final int ARRAY_FLOAT_INDEX_SCALE = theUnsafe .arrayIndexScale(float[].class); /** The value of {@code arrayIndexScale(double[].class)} */ public static final int ARRAY_DOUBLE_INDEX_SCALE = theUnsafe .arrayIndexScale(double[].class); /** The value of {@code arrayIndexScale(Object[].class)} */ public static final int ARRAY_OBJECT_INDEX_SCALE = theUnsafe .arrayIndexScale(Object[].class); //返回内存大小的单位。 public native int addressSize(); /** The value of {@code addressSize()} */ public static final int ADDRESS_SIZE = theUnsafe.addressSize(); // 返回内存页的大小 public native int pageSize(); // / random trusted operations from JNI: //告诉vm在具体内存地址定义一个类 public native Class<?> defineClass(String name, byte[] b, int off, int len, ClassLoader loader, ProtectionDomain protectionDomain); //要vm去定义一个匿名类 public native Class<?> defineAnonymousClass(Class<?> hostClass, byte[] data, Object[] cpPatches); //给cls类分配一个实例内存地址,而不掉用构造器 public native Object allocateInstance(Class<?> cls) throws InstantiationException; //抛出错误。并不会通知verifier public native void throwException(Throwable ee); //原子性的更新java变量 public final native boolean compareAndSwapObject(Object o, long offset, Object expected, Object x); /** * Atomically update Java variable to <tt>x</tt> if it is currently holding * <tt>expected</tt>. * * @return <tt>true</tt> if successful */ public final native boolean compareAndSwapInt(Object o, long offset, int expected, int x); /** * Atomically update Java variable to <tt>x</tt> if it is currently holding * <tt>expected</tt>. * * @return <tt>true</tt> if successful */ public final native boolean compareAndSwapLong(Object o, long offset, long expected, long x); //在o的offset偏移地址处,获取volatile类型的对象 public native Object getObjectVolatile(Object o, long offset); /** * Stores a reference value into a given Java variable, with volatile store * semantics. Otherwise identical to * {@link #putObject(Object, long, Object)} */ public native void putObjectVolatile(Object o, long offset, Object x); /** Volatile version of {@link #getInt(Object, long)} */ public native int getIntVolatile(Object o, long offset); /** Volatile version of {@link #putInt(Object, long, int)} */ public native void putIntVolatile(Object o, long offset, int x); /** Volatile version of {@link #getBoolean(Object, long)} */ public native boolean getBooleanVolatile(Object o, long offset); /** Volatile version of {@link #putBoolean(Object, long, boolean)} */ public native void putBooleanVolatile(Object o, long offset, boolean x); /** Volatile version of {@link #getByte(Object, long)} */ public native byte getByteVolatile(Object o, long offset); /** Volatile version of {@link #putByte(Object, long, byte)} */ public native void putByteVolatile(Object o, long offset, byte x); /** Volatile version of {@link #getShort(Object, long)} */ public native short getShortVolatile(Object o, long offset); /** Volatile version of {@link #putShort(Object, long, short)} */ public native void putShortVolatile(Object o, long offset, short x); /** Volatile version of {@link #getChar(Object, long)} */ public native char getCharVolatile(Object o, long offset); /** Volatile version of {@link #putChar(Object, long, char)} */ public native void putCharVolatile(Object o, long offset, char x); /** Volatile version of {@link #getLong(Object, long)} */ public native long getLongVolatile(Object o, long offset); /** Volatile version of {@link #putLong(Object, long, long)} */ public native void putLongVolatile(Object o, long offset, long x); /** Volatile version of {@link #getFloat(Object, long)} */ public native float getFloatVolatile(Object o, long offset); /** Volatile version of {@link #putFloat(Object, long, float)} */ public native void putFloatVolatile(Object o, long offset, float x); /** Volatile version of {@link #getDouble(Object, long)} */ public native double getDoubleVolatile(Object o, long offset); /** Volatile version of {@link #putDouble(Object, long, double)} */ public native void putDoubleVolatile(Object o, long offset, double x); /** * @description putObjectVolatile这个方法,并不会立刻保证可见性, * lazySet是使用Unsafe.putOrderedObject方法,这个方法在对低延迟代码是很有用的, * 它能够实现非堵塞的写入,这些写入不会被Java的JIT重新排序指令(instruction reordering), * 这样它使用快速的存储-存储(store-store) barrier, 而不是较慢的存储-加载(store-load) barrier, * 后者总是用在volatile的写操作上,这种性能提升是有代价的,虽然便宜,也就是写后结果并不会被其他线程看到, * 甚至是自己的线程,通常是几纳秒后被其他线程看到,这个时间比较短,所以代价可以忍受。 * 类似Unsafe.putOrderedObject还有unsafe.putOrderedLong等方法,unsafe.putOrderedLong比使用 volatile long要快3倍左右。. */ public native void putOrderedObject(Object o, long offset, Object x); /** Ordered/Lazy version of {@link #putIntVolatile(Object, long, int)} */ public native void putOrderedInt(Object o, long offset, int x); /** Ordered/Lazy version of {@link #putLongVolatile(Object, long, long)} */ public native void putOrderedLong(Object o, long offset, long x); //释放相关阻塞线程。获得信号量 public native void unpark(Object thread); //阻塞相关线程块,等待信号量 public native void park(boolean isAbsolute, long time); //根据给定的nelem,即loadavg查询系统负载。 public native int getLoadAverage(double[] loadavg, int nelems); // The following contain CAS-based Java implementations used on // platforms not supporting native instructions //以下是原子性相关的cas操作 //原子性int的自增。阻塞性的 public final int getAndAddInt(Object o, long offset, int delta) { int v; do { v = getIntVolatile(o, offset); } while (!compareAndSwapInt(o, offset, v, v + delta)); return v; } 原子性long的自增。 public final long getAndAddLong(Object o, long offset, long delta) { long v; do { v = getLongVolatile(o, offset); } while (!compareAndSwapLong(o, offset, v, v + delta)); return v; } //原子性的设置int值,也是阻塞式的。 public final int getAndSetInt(Object o, long offset, int newValue) { int v; do { v = getIntVolatile(o, offset); } while (!compareAndSwapInt(o, offset, v, newValue)); return v; } /** * Atomically exchanges the given value with the current value of a field or * array element within the given object <code>o</code> at the given * <code>offset</code>. * * @param o * object/array to update the field/element in * @param offset * field/element offset * @param newValue * new value * @return the previous value * @since 1.8 */ public final long getAndSetLong(Object o, long offset, long newValue) { long v; do { v = getLongVolatile(o, offset); } while (!compareAndSwapLong(o, offset, v, newValue)); return v; } /** * Atomically exchanges the given reference value with the current reference * value of a field or array element within the given object <code>o</code> * at the given <code>offset</code>. * * @param o * object/array to update the field/element in * @param offset * field/element offset * @param newValue * new value * @return the previous value * @since 1.8 */ public final Object getAndSetObject(Object o, long offset, Object newValue) { Object v; do { v = getObjectVolatile(o, offset); } while (!compareAndSwapObject(o, offset, v, newValue)); return v; } /** * Ensures lack of reordering of loads before the fence with loads or stores * after the fence. * @description 确保没有在写前面的重排序 * @since 1.8 */ public native void loadFence(); /** * Ensures lack of reordering of stores before the fence with loads or * stores after the fence. * @description 确保没有读相关重排序 * @since 1.8 */ public native void storeFence(); /** * Ensures lack of reordering of loads or stores before the fence with loads * or stores after the fence. * @description 确保读写重排序 * @since 1.8 */ public native void fullFence(); //被vm用于抛异常 private static void throwIllegalAccessError() { throw new IllegalAccessError(); }}
参考文档:
https://www.cnblogs.com/mickole/articles/3757278.html
https://stackoverflow.com/questions/23603304/java-8-unsafe-xxxfence-instructions
https://bugs.openjdk.java.net/browse/JDK-8038978
http://www.jdon.com/performance/java-performance-optimizations-queue.html
- Java并发学习(四)-sun.misc.Unsafe
- Java sun.misc.Unsafe
- Java中的sun.misc.Unsafe
- sun.misc.Unsafe类 学习小结
- Java中的sun.misc.Unsafe包
- Java Magic. Part 4: sun.misc.Unsafe
- Java源码剖析 sun.misc.Unsafe
- Java sun.misc.Unsafe 和 CAS
- Java中的sun.misc.Unsafe包
- sun.misc.Unsafe
- sun.misc.Unsafe
- sun.misc.Unsafe
- sun.misc.Unsafe源码
- sun.misc.Unsafe
- sun.misc.Unsafe源代码
- 认识 sun.misc.Unsafe
- 使用sun.misc.Unsafe
- sun.misc.Unsafe
- 快递鸟电子面单接口-电子面单解析方法
- 【Codevs1225】 八数码难题 BFS (1/1000)
- 使用Speedment实现事务处理
- FST基本操作
- 2014-03-06-codeblock中文乱码
- Java并发学习(四)-sun.misc.Unsafe
- 深度 | 苹果博客解读iPhone上的人脸识别深度神经网络
- C++基础知识
- Java Swing ~01
- elasticsearch mysql增量同步时区问题解决
- Android左右滑动标签页
- hdu-1686-Oulipo(KMP)
- Data Binding(数据绑定)用户指南
- luabind-0.9.1在windows、linux下的使用详解及示例