说明
- 为什么要整理Unsafe类的API呢?
- 因为在阅读JUC的源码的过程中,会发现大量使用了Unsafe类的API,如果不熟悉API的作用,那么阅读过程中多少会有点阻力。
API
- long objectFieldOffset(Field field)返回指定的变量在所属类中的内存偏移地址,该偏移地址仅仅在该Unsafe函数中访问指定字段时使用。
- 上面这句话很重要,理解这句话,这个类也就很简单了
static {
try {
valueOffset = unsafe.objectFieldOffset(AtomicLong.class.getDeclaredField("value"));
} catch (Exception ex) {
throw new Error(ex);
}
}
- int arrayBaseOffset(Class arrayClass)方法:获取数组中第一个元素的地址。
- int arrayIndexScale(Class arrayClass)方法:获取数组中一个元素占用的字节。
- boolean compareAndSwapLong(Object obj, long offset, long expect, long update)方法:比较对象obj中偏移量为offset的变量的值是否与expect相等,相等则使用update值更新,然后返回true,否则返回false。
- public native long getLongvolatile(Object obj, long offset)方法:获取对象obj中偏移量为offset的变量对应volatile语义的值。
- void putLongvolatile(Object obj, long offset, long value)方法:设置obj对象中offset偏移的类型为long的field的值为value,支持volatile语义。
- void putOrderedLong(Object obj, long offset, long value)方法:设置obj对象中offset偏移地址对应的long型field的值为value。这是一个有延迟的putLongvolatile方法,并且不保证值修改对其他线程立刻可见。只有在变量使用volatile修饰并且预计会被意外修改时才使用该方法。
- void park(boolean isAbsolute, long time)方法:阻塞当前线程,其中参数isAbsolute等于false且time等于0表示一直阻塞。
- long getAndSetLong(Object obj, long offset, long update)方法:获取对象obj中偏移量为offset的变量volatile语义的当前值,并设置变量volatile语义的值为update。
- long getAndAddLong(Object obj, long offset, long addValue)方法:获取对象obj中偏移量为offset的变量volatile语义的当前值,并设置变量值为原始值+addValue。
如何使用
获取Unsafe类注意事项
- 加载Unsafe必须是Bootstrap类加载器加载,否者会抛出安全异常,因此调用Unsafe.getUnsafe这个方法是不能用的
- 所以,必须通过反射来获取Unsafe对象
public class TestUnSafe {
static final Unsafe unsafe;
static final long stateOffset;
private volatile long state = 0;
static {
try { //使用反射获取Unsafe的成员变量
Field field = Unsafe.class.getDeclaredField("theUnsafe");
// 设置为可存取
field.setAccessible(true);
// 获取该变量的值
unsafe = (Unsafe) field.get(null);
//获取state在TestUnSafe中的偏移量
stateOffset = unsafe.objectFieldOffset(TestUnSafe.class.getDeclaredField("state"));
} catch (Exception ex) {
System.out.println(ex.getLocalizedMessage());
throw new Error(ex);
}
}}
参考:java并发编程之美2.9 Unsafe类