Java 知识-- Unsafe
本文最后更新于:4 个月前
⚡关于 unsafe
-
不能使用提供的 getInstance() 方法获取单例对象
unsafe 是单例的
private static final Unsafe unsafe = Unsafe.getUnsafe();
@CallerSensitive public static Unsafe getUnsafe() { Class var0 = Reflection.getCallerClass(); // 此处做了限制,非根类加载器 bootstrap class loader 调用会报错 if (!VM.isSystemDomainLoader(var0.getClassLoader())) { throw new SecurityException("Unsafe"); } else { return theUnsafe; } }
-
要想获得 unsafe 实例
-
反射
private static Unsafe reflectGetUnsafe() { try { Field field = Unsafe.class.getDeclaredField("theUnsafe"); field.setAccessible(true); return (Unsafe) field.get(null); } catch (Exception e) { log.error(e.getMessage(), e); return null; } }
-
修改 JVM 参数,把调用 Unsafe 相关方法的类 A 所在 jar 包路径追加到默认的 bootstrap 路径中,使得 A 被引导类加载器加载,从而通过 Unsafe.getUnsafe 方法安全的获取 Unsafe 实例。
java -Xbootclasspath/a: ${path} # 其中path为调用Unsafe相关方法的类所在jar包路径
-
⚡CAS 相关
// var2 字段值增加 var4
public final int getAndAddInt(Object var1, long var2, int var4) {
int var5;
// 自旋 + CAS
do {
// 获取当前对象 var1 中 var2 字段的地址值
// 即从内存中获取字段的真实值
var5 = this.getIntVolatile(var1, var2);
// 如果 CAS 失败,那么重试
// 如果成功,跳出循环
} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
return var5;
}
var2 这个偏移量是通过:
valueOffset = unsafe.objectFieldOffset(TargetObject.class.getDeclaredField("fileName"));
对于任意一个类要修改的字段,可以通过这种方式传入类名和字段名来获取对象字段的内存地址
本博客所有文章除特别声明外,均采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 。转载请注明出处!