1.介绍
Unsafe类提供了直接操控内存和底层线程的工作。Unsafe类是在sun.misc包下,不属于Java标准。但是很多Java的基础类库,包括一些被广泛使用的高性能开发库都是基于Unsafe类开发的,比如Netty、Cassandra、Hadoop、Kafka等。Unsafe类在提升Java运行效率,增强Java语言底层操作能力方面起了很大的作用。
2.线程的挂起与恢复
2.1 线程挂起
public native void park(boolean isAbsolute,long time)
- 当isAbsolute == false,表示不是绝对时间,即time=0;
- 当isAbsolute == true,表示是绝对时间,当阻塞的线程经过time时间后,线程阻塞自动消除。
- 当调用park方法后,线程阻塞。当别的线程调用unpark或者线程中断、或者超时阻塞线程将返回。
- 如果在调用park方法之前已经调用了unpark方法,那么线程不会阻塞。
2.2 线程恢复
public native void unpark(Object thread)
- 调用此方法使得阻塞的线程恢复运行
- 如果没有阻塞的线程,那么以后线程调用park()将不会阻塞
3.访问/修改对象变量值
3.1 获取对象字段的偏移量
public native long objectFieldOffset(Field f)
获取一个类字段的内存偏移地址。对于相同的类,相同的字段总是有相同的内存偏移地址。
如:
static {
try {
UNSAFE = sun.misc.Unsafe.getUnsafe();
Class<?> tk = Thread.class;
parkBlockerOffset = UNSAFE.objectFieldOffset
(tk.getDeclaredField("parkBlocker"));
SEED = UNSAFE.objectFieldOffset
(tk.getDeclaredField("threadLocalRandomSeed"));
PROBE = UNSAFE.objectFieldOffset
(tk.getDeclaredField("threadLocalRandomProbe"));
SECONDARY = UNSAFE.objectFieldOffset
(tk.getDeclaredField("threadLocalRandomSecondarySeed"));
} catch (Exception ex) { throw new Error(ex); }
}
3.2 修改对象字段的引用
public native void putInt(Object o,long offset,int x)
- Object o 是实例对象
- long offset是对象字段的偏移量
- x是要修改的值
3.3 访问对象字段的引用值
public native int getInt(Object o,long offset)
- Object o 是实例对象
- long offset是对象字段的偏移量
public native Object getObjectVolatile(Object o,
long offset)
与volatile原语获取字段的值
4. cas实现
public final native boolean compareAndSwapInt(Object o,
long offset,
int expected,
int x)
- except代表期望值。如果期望值跟内存中的值相等,则更新为x。否则不做修改,返回false
延迟写实现
public native void putOrderedObject(Object o,
long offset,
Object x)
public final void lazySet(V newValue) {
unsafe.putOrderedObject(this, valueOffset, newValue);
}
lazySet是使用Unsafe.putOrderedObject方法,这个方法在对低延迟代码是很有用的,它能够实现非堵塞的写入,这些写入不会被Java的JIT重新排序指令(instruction reordering),这样它使用快速的存储-存储(store-store) barrier, 而不是较慢的存储-加载(store-load) barrier, 后者总是用在volatile的写操作上,这种性能提升是有代价的,虽然便宜,也就是写后结果并不会被其他线程看到,甚至是自己的线程。
类似Unsafe.putOrderedObject还有unsafe.putOrderedLong等方法,unsafe.putOrderedLong比使用 volatile long要快3倍左右。.