美文网首页
Unsafe的使用解析

Unsafe的使用解析

作者: braveheart075 | 来源:发表于2018-12-10 21:54 被阅读0次

    相信很多人都阅读过jdk源码,这两天在看一段代码都时候正好用到Unsafe(JRE的rt.jar中提供了一个类sun.misc.Unsafe),特地研究了下Unsafe这个类。基于对象内存来进行操作对象。不安全。所以不建议使用。特别在concurrent包中都Atomicxxx类,底层都CAS 都用到了这个类。那么这个类究竟能干什么,我们先从实例化开始:

    • 首先,这个类是不能直接实例化到,但是可以通过反射来获取。
            sun.misc.Unsafe U = null;
    
            Field theUnsafeInstance = null;
            try {
                theUnsafeInstance = Unsafe.class.getDeclaredField("theUnsafe");
                theUnsafeInstance.setAccessible(true);
                U = (Unsafe) theUnsafeInstance.get(Unsafe.class);
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
    
    • 其次,我们一般会用到这个类到compareAndSwapXXX,这个方法是干嘛用的?官网解释如下: Screen Shot 2018-12-10 at 9.43.36 PM.png

      就是根据对象在内存的offset(我们叫他偏移量),来比较你期望的值和内存值是否相等,如果相等返回true,并进行swap,用最后一个x来进行swap。

    • 那么,我们来演示下:
      建一个对象:

    public class Main {
    
    
        private String s;
        private long s1;
        private long s2;
    
        public static void main(String[] args) {
            Main main = new Main();
            main.s1 = 20;
            long s, next;
            long state = 256;
            System.out.println(1 << 6);
            System.out.println(1 << 10);
            System.out.println(1L << 7);
            System.out.println("Hello World!");
            long except = 1;
            long real = 1;
            sun.misc.Unsafe U = null;
    
            Field theUnsafeInstance = null;
            try {
                theUnsafeInstance = Unsafe.class.getDeclaredField("theUnsafe");
                theUnsafeInstance.setAccessible(true);
                U = (Unsafe) theUnsafeInstance.get(Unsafe.class);
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
    
            System.out.println("========");
    
    //        Arrays.stream(Main.class.getDeclaredFields()).forEach(field -> System.out.println(U.objectFieldOffset(field.getName())));
    
            Field[] fields = Main.class.getDeclaredFields();
            for(Field field : fields) {
    
                System.out.println(field.getName()+ "=="+ U.objectFieldOffset(field));
            }
    
    
            System.out.println("========");
    
    
            boolean flag = U.compareAndSwapLong(main,16,21,21);
            System.out.println(flag);
            System.out.println(main.s1);
    
        }
    }
    
    • 我们看到了这个代码,有三个field。如何获得这三个field?如下这段代码发挥作用:
    Field[] fields = Main.class.getDeclaredFields();
    
    • 获取对象的偏移量:
            for(Field field : fields) {
    
                System.out.println(field.getName()+ "=="+ U.objectFieldOffset(field));
            }
    

    打印出来的结果如下:

    s==12
    s1==16
    s2==24
    

    这个数字就是offset。那么我们可以验证这个compare方法了。

    • 验证compare方法:我们将offset为16的内存变量s1改成21(原先是20)
    boolean flag = U.compareAndSwapLong(main,16,20,21);
    System.out.println(flag);
    System.out.println(main.s1);
    

    就是比较偏移量为16的内存对象值是否是20,如果是,改成21,打印结果如下:

    true
    21
    

    可以看到,如预期。好了,大家都知道类似的方法怎么用了吧。期望对大家有帮助。

    相关文章

      网友评论

          本文标题:Unsafe的使用解析

          本文链接:https://www.haomeiwen.com/subject/vufjhqtx.html