首页 > 代码库 > java编程之:Unsafe类

java编程之:Unsafe类

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 package com.yeepay.sxf.hashmaptest; 2  3 import java.lang.reflect.Field; 4  5 import sun.misc.Unsafe; 6  7 public class TestUnSafe { 8  9     public static void main(String[] args) throws NoSuchFieldException, 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         //打印年龄   打印结果:020         System.out.println("TestUnSafe.enclosing_method()"+player.getAge());21         22         player.setAge(100);23         24         //打印结果10025         System.out.println("TestUnSafe.main()"+player.getAge());26         27     }28     29 }30 31 /**32  * 普通类33  * @author sxf34  *35  */36 class Player{37     //年龄38     private int age=12;39     40     //构造函数私有化41     private Player(){42         this.age=50;43     }44 45     public int getAge() {46         return age;47     }48 49     public void setAge(int age) {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被<code>volatile</code>修饰并且期望被意外修改的时候使用才有用。
==>obj:  包含要修改field的对象
==>offset:    <code>obj</code>中整型field的偏移量
==>value:   field将被设置的新值

【五】
 public native void putOrderedLong(Object obj, long offset, long value);
==>设置obj对象中offset偏移地址对应的long型field的值为指定值。这是一个有序或者有延迟的<code>putLongVolatile</cdoe>方法,并且不保证值的改变被其他线程立即看到。只有在field被<code>volatile</code>修饰并且期望被意外修改的时候使用才有用。
==>obj:包含需要修改field的对象
==>offset:<code>obj</code>中long型field的偏移量
==>value:field将被设置的新值

【六】
  public native void putOrderedObject(Object obj, long offset, Object value);
==>设置obj对象中offset偏移地址对应的整型field的值为指定值。支持volatile store语义
==>obj:包含需要修改field的对象
==>offset:<code>obj</code>中整型field的偏移量
==>value:field将被设置的新值

【七】
public native void putIntVolatile(Object obj, long offset, int value);
==>设置obj对象中offset偏移地址对应的整型field的值为指定值。支持volatile store语义
==>obj: 包含需要修改field的对象
==>offset:<code>obj</code>中整型field的偏移量
==>value:field将被设置的新值


【八】
 public native int getIntVolatile(Object obj, long offset);
==>获取obj对象中offset偏移地址对应的整型field的值,支持volatile load语义。
==>obj: 包含需要去读取的field的对象
==>offset:<code>obj</code>中整型field的偏移量

【九】
 public native void putLongVolatile(Object obj, long offset, long value);
==>设置obj对象中offset偏移地址对应的long型field的值为指定值。
==>obj:包含需要修改field的对象
==>offset: <code>obj</code>中long型field的偏移量
==>value: field将被设置的新值

【十】
public native long getLongVolatile(Object obj, long offset);
==>获取obj对象中offset偏移地址对应的long型field的值,支持volatile load语义。
==> obj:包含需要去读取的field的对象
==>offset:<code>obj</code>中long型field的偏移量


【十一】
public native void putLong(Object obj, long offset, long value);
==>设置obj对象中offset偏移地址对应的long型field的值为指定值。
==>obj:包含需要修改field的对象
==>offset: <code>obj</code>中long型field的偏移量
==>value:field将被设置的新值


【十二】
public native long getLong(Object obj, long offset);
==> 获取obj对象中offset偏移地址对应的long型field的值
==>obj:包含需要去读取的field的对象
==>offset:<code>obj</code>中long型field的偏移量

【十三】
 public native void putObjectVolatile(Object obj, long offset, Object value);
==> 设置obj对象中offset偏移地址对应的object型field的值为指定值。
==>obj:包含需要修改field的对象
==>offset:<code>obj</code>中object型field的偏移量
==>value:field将被设置的新值

【十四】
public native Object getObjectVolatile(Object obj, long offset);
==>获取obj对象中offset偏移地址对应的object型field的值,支持volatile load语义。
==>obj:包含需要去读取的field的对象
==>offset:  <code>obj</code>中object型field的偏移量

【十五】
  public native int arrayBaseOffset(Class arrayClass);
==>获取给定数组中第一个元素的偏移地址。 为了存取数组中的元素,这个偏移地址与<a href="http://www.mamicode.com/#arrayIndexScale"><code>arrayIndexScale* </code></a>方法的非0返回值一起被使用
==>arrayClass:第一个元素地址被获取的class
==>返回:数组第一个元素 的偏移地址

【十六】
 public native int arrayIndexScale(Class arrayClass);
==>获取用户给定数组寻址的换算因子.一个合适的换算因子不能返回的时候(例如:基本类型), 返回0.这个返回值能够与<a href="http://www.mamicode.com/#arrayBaseOffset"><code>arrayBaseOffset</code> </a>一起使用去存取这个数组class中的元素

【十七】
public native void unpark(Thread thread);
==>释放被<a href="http://www.mamicode.com/#park"><code>park</code></a>创建的在一个线程上的阻塞.这个方法也可以被使用来终止一个先前调用<code>park</code>导致的阻塞.这个操作操作时不安全的,因此线程必须保证是活的.这是java代码不是native代码
==>thread:  要解除阻塞的线程

【十八】
public native void park(boolean isAbsolute, long time);
==>阻塞一个线程直到<a href="http://www.mamicode.com/#unpark"><code>unpark</code></a>出现、线程被中断或者timeout时间到期。如果一个<code>unpark</code>调用已经出现了,这里只计数。timeout为0表示永不过期.当<code>isAbsolute</code>为true时,timeout是相对于新纪元之后的毫秒。否则这个值就是超时前的纳秒数。这个方法执行时也可能不合理地返回(没有具体原因)
==>isAbsolute:如果为true timeout的值是一个相对于新纪元之后的毫秒数
==>time:  可以是一个要等待的纳秒数,或者是一个相对于新纪元之后的毫秒数直到到达这个时间点

java编程之:Unsafe类