Unsafe类在jdk 源码的多个类中用到,这个类的提供了一些绕开JVM的更底层功能,基于它的实现可以提高效率。但是,它是一把双刃剑:正如它的名字所预示的那样,它是 Unsafe的,它所分配的内存需要手动free(不被GC回收)。Unsafe类,提供了JNI某些功能的简单替代:确保高效性的同时,使事情变得更简 单。
这篇文章主要是以下文章的整理、翻译。
http://mishadoff.com/blog/java-magic-part-4-sun-dot-misc-dot-unsafe/
1. Unsafe API的大部分方法都是native实现,它由105个方法组成,主要包括以下几类:
(1)Info相关。主要返回某些低级别的内存信息:addressSize(), pageSize()
(2)Objects相关。主要提供Object和它的域操纵方法:allocateInstance(),objectFieldOffset()
(3)Class相关。主要提供Class和它的静态域操纵方法:staticFieldOffset(),defineClass(),defineAnonymousClass(),ensureClassInitialized()
(4)Arrays相关。数组操纵方法:arrayBaseOffset(),arrayIndexScale()
(5)Synchronization相关。主要提供低级别同步原语(如基于CPU的CAS(Compare-And-Swap)原 语):monitorEnter(),tryMonitorEnter(),monitorExit(),compareAndSwapInt(),putOrderedInt()
(6)Memory相关。直接内存访问方法(绕过JVM堆直接操纵本地内存):allocateMemory(),copyMemory(),freeMemory(),getAddress(),getInt(),putInt()
1 packagecom.yeepay.sxf.hashmaptest;2
3 importjava.lang.reflect.Field;4
5 importsun.misc.Unsafe;6
7 public classTestUnSafe {8
9 public static void main(String[] args) throwsNoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException, InstantiationException {10 //获取属性
11 Field f=Unsafe.class.getDeclaredField("theUnsafe");12 //13 f.setAccessible(true);14 //获取实例
15 Unsafe unsafe=(Unsafe) f.get(null);16
17 //实例化一个类
18 Player player=(Player) unsafe.allocateInstance(Player.class);19 //打印年龄 打印结果:0
20 System.out.println("TestUnSafe.enclosing_method()"+player.getAge());21
22 player.setAge(100);23
24 //打印结果100
25 System.out.println("TestUnSafe.main()"+player.getAge());26
27 }28
29 }30
31 /**
32 * 普通类33 *@authorsxf34 *35 */
36 classPlayer{37 //年龄
38 private int age=12;39
40 //构造函数私有化
41 privatePlayer(){42 this.age=50;43 }44
45 public intgetAge() {46 returnage;47 }48
49 public void setAge(intage) {50 this.age =age;51 }52 }
View Code
【一】
public native long objectFieldOffset(Field field);
==> 返回指定静态field的内存地址偏移量,在这个类的其他方法中这个值只是被用作一个访问
==>特定field的一个方式。这个值对于 给定的field是唯一的,并且后续对该方法的调用都应该返回相同的值
【二】
public native boolean compareAndSwapInt(Object obj, long offset, int expect, int update);
==>在obj的offset位置比较long field和期望的值,如果相同则更新。这个方法的操作应该是原子的,因此提供了一种不可中断的方式更新long field。成功返回true,不成功返回false
==>obj:包含要修改field的对象
==>offset:obj对象中long型field的偏移量
==>expect:希望field中存在的值
==>update:如果期望值expect与field的当前值相同,设置filed的值为这个新值
【三】
public native boolean compareAndSwapObject(Object obj, long offset, Object expect, Object update);
==>在obj的offset位置比较object field和期望的值,如果相同则更新。这个方法的操作应该是原子的,因此提供了一种不可中断的方式更新object field.成功返回true,不成功返回false
==>obj:包含要修改field的对象
==>offset:obj中object型field的偏移量
==>expect:希望field中存在的值
==>update:如果期望值expect与field的当前值相同,设置filed的值为这个新值
【四】
public native void putOrderedInt(Object obj, long offset, int value);
==>设置obj对象中offset偏移地址对应的整型field的值为指定值。这是一个有序或者有延迟的putIntVolatile方法,并且不保证值的改变被其他线程立即看到。只有在field被volatile
修饰并且期望被意外修改的时候使用才有用。
==>obj: 包含要修改field的对象
==>offset: obj
中整型field的偏移量
==>value: field将被设置的新值
【五】
public native void putOrderedLong(Object obj, long offset, long value);
==>设置obj对象中offset偏移地址对应的long型field的值为指定值。这是一个有序或者有延迟的putLongVolatile方法,并且不保证值的改变被其他线程立即看到。只有在field被
volatile
修饰并且期望被意外修改的时候使用才有用。
==>obj:包含需要修改field的对象
==>offset:obj
中long型field的偏移量
==>value:field将被设置的新值
【六】
public native void putOrderedObject(Object obj, long offset, Object value);
==>设置obj对象中offset偏移地址对应的整型field的值为指定值。支持volatile store语义
==>obj:包含需要修改field的对象
==>offset:obj
中整型field的偏移量
==>value:field将被设置的新值
【七】
public native void putIntVolatile(Object obj, long offset, int value);
==>设置obj对象中offset偏移地址对应的整型field的值为指定值。支持volatile store语义
==>obj: 包含需要修改field的对象
==>offset:obj
中整型field的偏移量
==>value:field将被设置的新值
【八】
public native int getIntVolatile(Object obj, long offset);
==>获取obj对象中offset偏移地址对应的整型field的值,支持volatile load语义。
==>obj: 包含需要去读取的field的对象
==>offset:obj
中整型field的偏移量
【九】
public native void putLongVolatile(Object obj, long offset, long value);
==>设置obj对象中offset偏移地址对应的long型field的值为指定值。
==>obj:包含需要修改field的对象
==>offset: obj
中long型field的偏移量
==>value: field将被设置的新值
【十】
public native long getLongVolatile(Object obj, long offset);
==>获取obj对象中offset偏移地址对应的long型field的值,支持volatile load语义。
==> obj:包含需要去读取的field的对象
==>offset:obj
中long型field的偏移量
【十一】
public native void putLong(Object obj, long offset, long value);
==>设置obj对象中offset偏移地址对应的long型field的值为指定值。
==>obj:包含需要修改field的对象
==>offset: obj
中long型field的偏移量
==>value:field将被设置的新值
【十二】
public native long getLong(Object obj, long offset);
==> 获取obj对象中offset偏移地址对应的long型field的值
==>obj:包含需要去读取的field的对象
==>offset:obj
中long型field的偏移量
【十三】
public native void putObjectVolatile(Object obj, long offset, Object value);
==> 设置obj对象中offset偏移地址对应的object型field的值为指定值。
==>obj:包含需要修改field的对象
==>offset:obj
中object型field的偏移量
==>value:field将被设置的新值
【十四】
public native Object getObjectVolatile(Object obj, long offset);
==>获取obj对象中offset偏移地址对应的object型field的值,支持volatile load语义。
==>obj:包含需要去读取的field的对象
==>offset: obj
中object型field的偏移量
【十五】
public native int arrayBaseOffset(Class arrayClass);
==>获取给定数组中第一个元素的偏移地址。 为了存取数组中的元素,这个偏移地址与arrayIndexScale*
方法的非0返回值一起被使用
==>arrayClass:第一个元素地址被获取的class
==>返回:数组第一个元素 的偏移地址
【十六】
public native int arrayIndexScale(Class arrayClass);
==>获取用户给定数组寻址的换算因子.一个合适的换算因子不能返回的时候(例如:基本类型), 返回0.这个返回值能够与arrayBaseOffset
一起使用去存取这个数组class中的元素
【十七】
public native void unpark(Thread thread);
==>释放被park
创建的在一个线程上的阻塞.这个方法也可以被使用来终止一个先前调用park
导致的阻塞.这个操作操作时不安全的,因此线程必须保证是活的.这是java代码不是native代码
==>thread: 要解除阻塞的线程
【十八】
public native void park(boolean isAbsolute, long time);
==>阻塞一个线程直到unpark
出现、线程被中断或者timeout时间到期。如果一个unpark
调用已经出现了,这里只计数。timeout为0表示永不过期.当isAbsolute
为true时,timeout是相对于新纪元之后的毫秒。否则这个值就是超时前的纳秒数。这个方法执行时也可能不合理地返回(没有具体原因)
==>isAbsolute:如果为true timeout的值是一个相对于新纪元之后的毫秒数
==>time: 可以是一个要等待的纳秒数,或者是一个相对于新纪元之后的毫秒数直到到达这个时间点