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

原创粉丝点击