Java - Unsafe 源码阅读笔记

in Tech Java

简介

  Unsafe类提供一组用于执行低级、不安全操作的方法。提供的主要功能有:

虽然类和所有方法都是公共的,但是只有受信任的代码才能获得它的实例。也就是直接new的话,会报错构造方法是私有的。同时该类用final修饰,也就是不允许继承。但是仍然可以通过反射获取实例。

示例

通过反射使用Unsafe更新成员变量

public class UnsafeTest {
    public int value = -1;
    public volatile long offset;

    {
        try {
            // 获取成员变量的偏移量
            offset = getUnsafe().objectFieldOffset(UnsafeTest.class.getDeclaredField("value"));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws Exception {
        UnsafeTest test = new UnsafeTest();
        test.update(-1, 1);
    }

    public void update(int expected, int update) throws Exception {
        if (getUnsafe().compareAndSwapInt(this, offset, expected, update))
            System.out.println(value);
    }

    public Unsafe getUnsafe() throws IllegalAccessException {
        // 反射获取Unsafe类的第一个成员变量,也就是Unsafe内部实例
        Field unsafeField = Unsafe.class.getDeclaredFields()[0];
        // 修改访问权限
        unsafeField.setAccessible(true);
        Unsafe unsafe = (Unsafe) unsafeField.get(null);
        return unsafe;
    }
}

Unsafe 类

public final class Unsafe {
    private static final Unsafe theUnsafe;
    public static final int INVALID_FIELD_OFFSET = -1;
    public static final int ARRAY_BOOLEAN_BASE_OFFSET;
    public static final int ARRAY_BYTE_BASE_OFFSET;
    public static final int ARRAY_SHORT_BASE_OFFSET;
    public static final int ARRAY_CHAR_BASE_OFFSET;
    public static final int ARRAY_INT_BASE_OFFSET;
    public static final int ARRAY_LONG_BASE_OFFSET;
    public static final int ARRAY_FLOAT_BASE_OFFSET;
    public static final int ARRAY_DOUBLE_BASE_OFFSET;
    public static final int ARRAY_OBJECT_BASE_OFFSET;
    public static final int ARRAY_BOOLEAN_INDEX_SCALE;
    public static final int ARRAY_BYTE_INDEX_SCALE;
    public static final int ARRAY_SHORT_INDEX_SCALE;
    public static final int ARRAY_CHAR_INDEX_SCALE;
    public static final int ARRAY_INT_INDEX_SCALE;
    public static final int ARRAY_LONG_INDEX_SCALE;
    public static final int ARRAY_FLOAT_INDEX_SCALE;
    public static final int ARRAY_DOUBLE_INDEX_SCALE;
    public static final int ARRAY_OBJECT_INDEX_SCALE;
    public static final int ADDRESS_SIZE;
...
}

构造方法

    private Unsafe() {
    }

普通读写

基本数据类型和包装类都可以。私有的也可以读写。余下类似

getInt() 方法

    public native int getInt(Object o, long offset);

putInt() 方法

    public native void putInt(Object o, long offset, int x);

getObject() 方法

    public native Object getObject(Object o, long offset);

putObject() 方法

    public native void putObject(Object o, long offset, Object x);

volatile读写

普通的读写无法保证可见性和有序性,而volatile读写就可以保证可见性和有序性。由此volatile读写消耗更多性能

getIntVolatile() 方法

    public native int getIntVolatile(Object o, long offset);

putIntVolatile() 方法

    public native void putIntVolatile(Object o, long offset, int x);

有序写入

有序写入只保证写入的有序性,不保证可见性,就是说一个线程的写入不保证其他线程立马可见。消耗性能介于普通读写和volatile读写之间。

putOrderedObject() 方法

    public native void putOrderedObject(Object o, long offset, Object x);

putOrderedInt() 方法

    public native void putOrderedInt(Object o, long offset, int x);

putOrderedLong() 方法

    public native void putOrderedLong(Object o, long offset, long x);

直接内存操作

allocateMemory() 方法

分配内存

    public native long allocateMemory(long bytes);

reallocateMemory() 方法

重新分配内存

    public native long reallocateMemory(long address, long bytes);

setMemory() 方法

内存初始化

    public native void setMemory(Object o, long offset, long bytes, byte value);

copyMemory() 方法

内存复制

    public native void copyMemory(Object srcBase, long srcOffset,Object destBase, long destOffset,long bytes);

freeMemory() 方法

清除内存

    public native void freeMemory(long address);

CAS相关

JUC中大量被使用到的CAS操作

compareAndSwapObject() 方法

    public final native boolean compareAndSwapObject(Object o, long offset, Object expected, Object x);

compareAndSwapInt() 方法

    public final native boolean compareAndSwapInt(Object o, long offset, int expected, int x);

compareAndSwapLong() 方法

    public final native boolean compareAndSwapLong(Object o, long offset, long expected, long x);

偏移量相关

staticFieldOffset() 方法

获取静态字段偏移量

    public native long staticFieldOffset(Field f);

获取普通字段偏移量

objectFieldOffset() 方法

    public native long objectFieldOffset(Field f);

staticFieldBase() 方法

返回Field所在的对象

    public native Object staticFieldBase(Field f);

arrayBaseOffset() 方法

获取数组起始偏移量

    public native int arrayBaseOffset(Class<?> arrayClass);

arrayIndexScale() 方法

获取数组单个元素偏移量

    public native int arrayIndexScale(Class<?> arrayClass);

线程调度

park() 方法

阻塞线程

    public native void park(boolean isAbsolute, long time);

unpark() 方法

唤醒线程

    public native void unpark(Object thread);

monitorEnter() 方法

加锁(synchronized)

    public native void monitorEnter(Object o);

monitorExit() 方法

解锁(synchronized)

    public native void monitorExit(Object o);

tryMonitorEnter() 方法

尝试加锁

    public native boolean tryMonitorEnter(Object o);

类加载

defineClass() 方法

动态地创建类

    public native Class<?> defineClass(String name, byte[] b, int off, int len, ClassLoader loader, ProtectionDomain protectionDomain);

defineAnonymousClass() 方法

动态创建一个匿名内部类

    public native Class<?> defineAnonymousClass(Class<?> hostClass, byte[] data, Object[] cpPatches);

allocateInstance() 方法

创建一个类的实例,但是不会调用这个实例的构造方法,如果这个类还未被初始化,则初始化这个类

    public native Object allocateInstance(Class<?> cls) throws InstantiationException;

shouldBeInitialized() 方法

判断是否需要初始化一个类

    public native boolean shouldBeInitialized(Class<?> c);

ensureClassInitialized() 方法

保证已经初始化过一个类

    public native void ensureClassInitialized(Class<?> c);

内存屏障

loadFence() 方法

保证在这个屏障之前的所有读操作都已经完成

public native void loadFence();

storeFence() 方法

保证在这个屏障之前的所有写操作都已经完成

public native void storeFence();

fullFence() 方法

保证在这个屏障之前的所有读写操作都已经完成

public native void fullFence();

参考来源:

https://www.jianshu.com/p/db8dce09232d
http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/classes/sun/misc/Unsafe.java