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