sun.misc.Unsafe
作用:可以用来在任意内存地址位置处读写数据,支持一些CAS原子操作
Java最初被设计为一种安全的受控环境。尽管如此,HotSpot还是包含了一个后门sun.misc.Unsafe,提供了一些可以直接操控内存和线程的底层操作。Unsafe被JDK广泛应用于java.nio和并发包等实现中,这个不安全的类提供了一个观察HotSpot JVM内部结构并且可以对其进行修改,但是不建议在生产环境中使用
获取Unsafe实例
Unsafe对象不能直接通过new Unsafe()或调用Unsafe.getUnsafe()获取,原因如下:
- 不能直接new Unsafe(),原因是Unsafe被设计成单例模式,构造方法是私有的;
- 不能通过调用Unsafe.getUnsafe()获取,因为getUnsafe被设计成只能从引导类加载器(bootstrap class loader)加载
@CallerSensitive
public static Unsafe getUnsafe() {
Class var0 = Reflection.getCallerClass();
if (!VM.isSystemDomainLoader(var0.getClassLoader())) {
throw new SecurityException("Unsafe");
} else {
return theUnsafe;
}
}
获取实例
//方法一:我们可以令我们的代码“受信任”。运行程序时,使用bootclasspath选项,指定系统类路径加上你使用的一个Unsafe路径
java -Xbootclasspath:/usr/jdk1.7.0/jre/lib/rt.jar:. com.mishadoff.magic.UnsafeClient
// 方法二
static {
try {
Field field = Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
UNSAFE = (Unsafe) field.get(null);
} catch (Exception e) {
}
}
注意:忽略你的IDE。比如:eclipse显示”Access restriction…”错误,但如果你运行代码,它将正常运行。如果这个错误提示令人烦恼,可以通过以下设置来避免:
Preferences -> Java -> Compiler -> Errors/Warnings -> Deprecated and restricted API -> Forbidden reference -> Warning
重点API
- allocateInstance(Class<?> var1)不调用构造方法生成对象
User instance = (User) UNSAFE.allocateInstance(User.class);
- objectFieldOffset(Field var1)返回成员属性在内存中的地址相对于对象内存地址的偏移量
- putLong,putInt,putDouble,putChar,putObject等方法,直接修改内存数据(可以越过访问权限)
package com.quancheng;
import sun.misc.Unsafe;
import java.lang.reflect.Field;
public class CollectionApp {
private static sun.misc.Unsafe UNSAFE;
public static void main(String[] args) {
try {
User instance = (User) UNSAFE.allocateInstance(User.class);
instance.setName("luoyoub");
System.err.println("instance:" + instance);
instance.test();
Field name = instance.getClass().getDeclaredField("name");
UNSAFE.putObject(instance, UNSAFE.objectFieldOffset(name), "huanghui");
instance.test();
} catch (Exception e) {
e.printStackTrace();
}
}
static {
try {
Field field = Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
UNSAFE = (Unsafe) field.get(null);
} catch (Exception e) {
}
}
}
class User {
private String name;
public void setName(String name) {
thi