如何正确创建UnSafe实例
Long offset = Unsafe.getUnsafe().objectFieldOffset(nameField);
unsafe.compareAndSwapObject(targetInstance,offset,name,"hello unsafe");
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6WcFdrp5-1628667545948)(/Users/tim/Desktop/截屏2021-08-11 上午10.27.16.png)]
查看getUnsafe方法,会判断当前类的class loader是否为null,但当前类的加载器是AppClassLoader实例,所以这里判断为真,抛出上面的异常。所以只能用BootstrapClassLoader加载器中调用的类使用这个unsage,比如concurrenthashmap是在BootstrapClassLoader中加载的,getClassLoader0()获取出来是为null的,所以不会抛出异常。
@CallerSensitive
public static Unsafe getUnsafe() {
Class var0 = Reflection.getCallerClass();
if (!VM.isSystemDomainLoader(var0.getClassLoader())) {
throw new SecurityException("Unsafe");
} else {
return theUnsafe;
}
}
public static boolean isSystemDomainLoader(ClassLoader var0) {
return var0 == null;
}
那如何得到UnSafe的实例呢?因为Unsafe中有个theUnsafe的属性,该属性在static静态代码块中被实例化类,所以可以通过放射来获取这个已经实例化的对象属性,从而获得unsafe对象:
static {
registerNatives();
Reflection.registerMethodsToFilter(Unsafe.class, new String[]{"getUnsafe"});
theUnsafe = new Unsafe();
...
}
如何使用UnSafe进行反射?
创建一个反射的目标类用于后面的例子
public class Hello {
private String name;
public void hello(String name){
System.out.println("hello "+name);
}
public void say(String name){
System.out.println("say "+name);
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
通过UnSafe操作目标对象的属性
//通过反射拿到Unsafe类的成员theUnsafe,该成员已经在UnSafe类的静态代码块中被实例化了
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
Unsafe unsafe = (Unsafe) theUnsafe.get(null);
Class clazz = Hello.class;
Field nameField = clazz.getDeclaredField("name");
nameField.setAccessible(true);
Hello targetInstance = new Hello();
//这里可以使用反射拿到成员变量theUnsafe
Long offset = unsafe.objectFieldOffset(nameField);
unsafe.compareAndSwapObject(targetInstance,offset,name,"hello unsafe");
String name = (String) unsafe.getObject(targetInstance,offset);
System.out.println("name: "+name);
结语
当然UnSafe还有内存操作、内存屏障、线程调度等功能,后续会有专题文章。