Java中邪恶的Unsafe,一半天使一半魔鬼-刘宇

一、什么是
Java和C++语言的一个重要区别就是Java中我们无法直接操作一块内存区域 , 不能像C++中那样可以自己申请内存和释放内存 。Java中的类为我们提供了类似C++手动管理内存的能力 。
类 , 全限定名是sun.misc. , 从名字中我们可以看出来这个类对普通程序员来说是“危险”的 , 一般应用开发者不会用到这个类 。类是"final"的 , 不允许继承 , 且构造函数是的 , 因此我们无法在外部对进行实例化 。
二、获取
虽然是无法被实例化的 , 但是我们可以通过反射获取到 。
private static Unsafe getUnsafe(){Field field = null;Unsafe unsafe = null;try {field = Unsafe.class.getDeclaredField("theUnsafe");field.setAccessible(true);unsafe = (Unsafe) field.get(null);} catch (Exception e) {e.printStackTrace();}return unsafe;}
三、的功能汇总
1、内存操作
// 分配内存, 相当于C++的malloc函数public native long allocateMemory(long bytes);// 扩充内存public native long reallocateMemory(long address, long bytes);// 释放内存public native void freeMemory(long address);// 在给定的内存块中设置值public native void setMemory(Object o, long offset, long bytes, byte value);// 内存拷贝public native void copyMemory(Object srcBase, long srcOffset, Object destBase, long destOffset, long bytes);// 获取给定地址值 , 忽略修饰限定符的访问限制 。与此类似操作还有: getInt , getDouble , getLong , getChar等public native Object getObject(Object o, long offset);// 为给定地址设置值 , 忽略修饰限定符的访问限制 , 与此类似操作还有: putInt,putDouble , putLong , putChar等public native void putObject(Object o, long offset, Object x);// 获取给定地址的byte类型的值(当且仅当该内存地址为allocateMemory分配时 , 此方法结果为确定的)public native byte getByte(long address);// 为给定地址设置byte类型的值(当且仅当该内存地址为allocateMemory分配时 , 此方法结果才是确定的)public native void putByte(long address, byte x);
2、CAS相关
public final native boolean compareAndSwapObject(Object o, long offset,Object expected, Object update);public final native boolean compareAndSwapInt(Object o, long offset, int expected,int update);public final native boolean compareAndSwapLong(Object o, long offset, long expected, long update);
3、线程调度
//取消阻塞线程public native void unpark(Object thread);//阻塞线程public native void park(boolean isAbsolute, long time);//获得对象锁(可重入锁)@Deprecatedpublic native void monitorEnter(Object o);//释放对象锁@Deprecatedpublic native void monitorExit(Object o);//尝试获取对象锁@Deprecatedpublic native boolean tryMonitorEnter(Object o);
4、Class相关
//获取给定静态字段的内存地址偏移量 , 这个值对于给定的字段是唯一且固定不变的public native long staticFieldOffset(Field f);//获取一个静态类中给定字段的对象指针public native Object staticFieldBase(Field f);//判断是否需要初始化一个类 , 通常在获取一个类的静态属性的时候(因为一个类如果没初始化 , 它的静态属性也不会初始化)使用 。当且仅当ensureClassInitialized方法不生效时返回false 。public native boolean shouldBeInitialized(Class c);//检测给定的类是否已经初始化 。通常在获取一个类的静态属性的时候(因为一个类如果没初始化 , 它的静态属性也不会初始化)使用 。public native void ensureClassInitialized(Class