Unsafe性质
- sun.misc.Unsafe,“后门”类,可以直接操控内存和线程的底层操作,应用于java.nio和并发包等实现
- Unsafe是final类,不能被继承
-获取Unsafe实例的"唯一"正常手段:
Unsafe unsafe = Unsafe.getUnsafe();
因为有使用限制,看源码就知道了
//构造器私有
private Unsafe() {}
@CallerSensitive
public static Unsafe getUnsafe() {
Class var0 = Reflection.getCallerClass();
//只能被Bootloader加载
if (!VM.isSystemDomainLoader(var0.getClassLoader())) {
throw new SecurityException("Unsafe");
} else {
return theUnsafe;
}
}
当然,通过反射也可以获取Unsafe实例:
public static Unsafe getUnsafe() {
try {
Field f = Unsafe.class.getDeclaredField("theUnsafe");
f.setAccessible(true);
return (Unsafe)f.get(null);
} catch (Exception e) {
/* ... */
}
}
常用方法
(下文中用到的XXX指参数类型,Unsafe类方法都至少支持三种类型:int、long、object)
注意偏移量都是long类型
-
objectFieldOffset:获取到指定实例变量(即非静态属性),在对象内存中的偏移量
因为在别的很多方法中都需要偏移量,所以一般都会先调用这个方法,而且会用常量保留这个偏移量,方便使用。
// 参数是Field public native long objectFieldOffset(Field var1); 所以使用eg: long offset = UNSAFE.objectFieldOffset (UnsafeTest.class.getDeclaredField("state"));
本方法的object不是指类型为Object,而是指实例变量
即不存在intFieldOffset、longFieldOffset等方法,别混乱了。
而获取静态属性的方法就是staticFieldOffset()
//用法一样,但获取的是静态属性的偏移地址 public native long staticFieldOffset(Field var1);
-
compareAndSwapXXX:通过比较并替换的机制,修改指定偏移量内存的值
/** * @param var1 对象实例,所以该值经常为 this,指当前实例,值得注意的是数组若为对象类型,那放入数组元素也是可行的 * @param var2 偏移量 * @param var4 期望的旧值 * @param var5 更换的新值 * @return CAS操作是否成功 */ public final native boolean compareAndSwapXXX (Object var1, long var2, XXX var4, XXX var5);
compareAndSwapXXX只支持上述三种类型
-
对volatile变量的get、set方法
本方法则支持八大基本类型 + object
/**
* @param var1 对象实例
* @param var2 偏移量
*/
public native XXX getXXXVolatile(Object var1, long var2);
/**
* @param var1 对象实例
* @param var2 偏移量
* @param var4 需要设置的新值
*/
public native void putXXXVolatile
(Object var1, long var2, XXX var4);
-
其余的getAndSetXXX / getAndAddXXX (也只支持那三个类型)
也是通过上述方法配合实现
-
park、unpark方法,用于挂起 / 唤醒某一线程
本文完,若有误欢迎指出。
参考资料:
java中的Unsafe