• 反射、Unsafe、直接调用性能大比拼


      在java动态表达式、原生调用、反射性能对比这一篇的基础上,本文我们将比较原生调用和直接通过Unsafe指针操作java对象的性能。

    package com.hundsun.jrescloud;
    
    import sun.misc.Unsafe;
    
    import java.lang.reflect.Field;
    
    /**
     * @author zjhua
     * @description
     * @date 2020/1/26 20:20
     */
    public class TestUnSafe {
        static final Unsafe unsafe;
        static final long stateOffset;
        static final long volStateOffset;
        private volatile long volState = 0;
        private long state = 0;
    
        static {
            try {
                Field field = Unsafe.class.getDeclaredField("theUnsafe");   # 对于不在rt.jar下的类,只能通过反射获取Unsafe实例,否则会发生安全越界
                field.setAccessible(true);
                unsafe = (Unsafe) field.get(null);
                stateOffset = unsafe.objectFieldOffset(TestUnSafe.class.getDeclaredField("state"));
                volStateOffset = unsafe.objectFieldOffset(TestUnSafe.class.getDeclaredField("volState"));
            } catch (Exception ex) {
                System.out.println(ex.getLocalizedMessage());
                throw new Error(ex);
            }
        }
    
        public static void main(String[] args) {
            TestUnSafe test = new TestUnSafe();
            long beg = System.currentTimeMillis();
            for (int i = 0; i < 100000000; i++) {
                unsafe.putLong(test, stateOffset,i);
            }
            System.out.println("unsafe put non volatile: " + (System.currentTimeMillis() - beg));
            beg = System.currentTimeMillis();
            for (int i = 0; i < 100000000; i++) {
                test.state = i;
            }
            System.out.println("pojo put non volatile: " + (System.currentTimeMillis() - beg));
    
            beg = System.currentTimeMillis();
            for (int i = 0; i < 100000000; i++) {
                unsafe.putLong(test, stateOffset,i);
            }
            System.out.println("unsafe put volatile: " + (System.currentTimeMillis() - beg));
            beg = System.currentTimeMillis();
            for (int i = 0; i < 100000000; i++) {
                test.volState = i;
            }
            System.out.println("pojo put volatile: " + (System.currentTimeMillis() - beg));
        }
    }

      输出如下:

    unsafe put non volatile: 179  // 普通属性,直接操作更快。如果使用setter的话,则有时候unsafe快,有时候pojo快。按说unsafe直接通过指针操作,至少不应该更慢才对,所以唯一的原因应该是方法调用本身的损耗。
    pojo put non volatile: 68  
    unsafe put volatile: 114   // volatile属性,unsafe要快近6倍。
    pojo put volatile: 795

      对于字符串操作,上述结论亦成立,所有的JUC包中的原子类AtomicXXX都是通过Unsafe实现的,其底层的各compareAndSwapXXX方法都是JNI实现。

      除了get/put外,Unsafe类还包含很多CAS(cas作为一种优化方式,其代价是cpu利用率在冲突高的时候很厉害,此时锁更合理)功能(JUC很多原子和CAS就是基于Unsafe实现)、park、unpark功能,LockSupport工具类就是调用的Unsafe的park与unpark实现的。

      注:Reflection.getCallerClass(n)已经被废弃,不应该再使用,它主要用来跟踪哪些类调用了本方法,不过Reflection.getCallerClass()仍然可用,在跟踪工具类的时候时还是比较有用的。

      关于Unsafe更全面的使用介绍,可以参见https://my.oschina.net/editorial-story/blog/3019773。

  • 相关阅读:
    教务管理系统(node+express+mysql)
    poj 2485 Highways 超级大水题 kruscal
    HDU 1874 畅通工程续 + HDU 2544 最短路 最短路水题,floyd水
    HEX格式转BIN格式 MOT格式转BIN格式
    html的标签一共有多少个?
    同时存在n个线程(n>5),需要写入或者读取一个名为test.txt的文件
    poj 1258 AgriNet 水题三连发。。。又是kruscal
    招投标专家库
    poj 1789 kruscal水题
    仿Word自动套用格式,用CSS设置表格样式
  • 原文地址:https://www.cnblogs.com/zhjh256/p/10741400.html
Copyright © 2020-2023  润新知