• 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         //打印年龄   打印结果: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  * @author sxf
    34  *
    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="#arrayIndexScale"><code>arrayIndexScale* </code></a>方法的非0返回值一起被使用
    ==>arrayClass:第一个元素地址被获取的class
    ==>返回:数组第一个元素 的偏移地址

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

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

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

  • 相关阅读:
    反射入门
    把数据库表的信息添加到list集合里面
    简单的事务分析及使用
    java-web与jdbc 的使用
    菜鸟入门bootstrap
    如何彻底的卸载mysql
    发生系统错误 1067,解决方案
    纯js的购物车案例
    idea里面怎么把自己项目添加maven
    js入门
  • 原文地址:https://www.cnblogs.com/shangxiaofei/p/5813559.html
Copyright © 2020-2023  润新知