Java并发学习(四)-sun.misc.Unsafe

版权声明:本博客所有的原创文章,转载请注明出处,作者皆保留版权。 https://blog.csdn.net/anLA_/article/details/78631026

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

没有更多推荐了,返回首页