zoukankan      html  css  js  c++  java
  • 深入CAS原理

    JDK中所有的CAS到最后都要用到这个方法:

    public final native boolean compareAndSwapObject(Object var1, long var2, Object var4, Object var5);

    这个方法有4个参数,奇怪的是序号不是1234,而是1245,没有javadoc和任何注释,是个native方法,代码实现是用C++写的。

    这个方法到底干什么的?

    下面来分析这个几个参数:

    Object var1是要修改的目标对象。
    long var2是要修改的对象的属性,为什么是整数,因为传入C++时,通过var1这个结构体指针和偏离值得到字段的。
    这个偏离值怎么获得,通过下面这个方法,next是字段名:
    UNSAFE.objectFieldOffset(k.getDeclaredField("next"));
    Node对象有个属性next,cas方法compareAndSwapObject要修改的就是Node对象的next属性值,通过得到这个next的参数的偏离值比如12,来修改它。
    Object var4是要对比的值,拿var4和Node对象的next属性对比,如果相同就用var5替换
    Object var5要拿来替换的对象。

    完整的代码如下:

    import sun.misc.Unsafe;
    
    import java.lang.reflect.Field;
    import java.util.Objects;
    
    /**
     * Created by TangHaiyang on 2019/8/19.
     * 验证cas的关键方法objectFieldOffset
     */
    public class TestUnsafe {
    
        public static void main(String[] args) {
            Node node = new Node();
            node.seq=10;
    
            Node node2 = new Node();
            node2.seq=20;
    
            Node node3 = new Node();
            node3.seq=20;
    
            System.out.println(node2.equals(new Node()));
            System.out.println(node2.equals(node3));
    
            /**
             * 原子操作, 通过CAS方法更新node的next属性
             * 是否等于null,等于则用new node()替换并返回true,否则不做任何操作并返回false
             * 在jdk源码的下面几个集合中广泛用到了compareAndSwapObject,通常是跟null对比然后替换为指定的对象
             * ConcurrentHashMap
             * ConcurrentLinkedQueue
             * ConcurrentSkipListMap
             * ConcurrentLinkedDeque
             * SynchronousQueue
             */
            boolean flag1 = node.casNext(null,new Node());
            boolean flag2 = node.casNext(null,new Node());
            boolean flag3 = node.casNext(node2,new Node());
            System.out.println(flag1);
            System.out.println(flag2);
            System.out.println(flag3);
        }
    
        private static class Node{
            volatile Node next;
            volatile int seq;
            private static final sun.misc.Unsafe UNSAFE;
            private static final long nextOffset;
            static {
                try {
                    /*
                    sun.misc.Unsafe.getUnsafe()会得到一个SecurityException,这个类只有被JDK信任的类才能通过这个方法实例化
                    但是可以通过反射拿到对应的实例
                    UNSAFE = sun.misc.Unsafe.getUnsafe();
                    */
                    UNSAFE = getUnsafe();
                    Class<?> k = Node.class;
                    if(Objects.isNull(UNSAFE)) {
                        nextOffset = 0;
                    }else {
                        nextOffset = UNSAFE.objectFieldOffset(k.getDeclaredField("next"));
                    }
                } catch (Exception e) {
                    throw new Error(e);
                }
            }
    
            /**
             * 使用Unsafe CAS方法
             * @param cmp 目标值与cmp比较equal方法,如果相等就更新返回true;如果不相等就不更新返回false;
             * @param val 需要更新的值;
             * @return boolean
             */
            boolean casNext(Node cmp, Node val) {
                /*
                 * compareAndSwapObject(Object var1, long var2, Object var3, Object var4)
                 * var1 操作的对象
                 * var2 操作的对象属性是个偏离值,对C++的结构体来说,var1是指针,指针加偏离值就能得到结构体成员,相当远java对象属性
                 * var3 var2对应的属性与var3比较,相等才更新
                 * var4 更新值
                 */
                return UNSAFE.compareAndSwapObject(this, nextOffset, cmp, val);
            }
    
            /**
             * 获取Unsafe的方法
             * 获取了以后就可以愉快的使用CAS啦
             * @return Unsafe
             */
            private static Unsafe getUnsafe() {
                try {
                    Field f = Unsafe.class.getDeclaredField("theUnsafe");
                    f.setAccessible(true);
                    return (Unsafe)f.get(null);
                } catch (Exception e) {
                    return null;
                }
            }
        }
    }
  • 相关阅读:
    中国MOOC分数——Java
    axios的封装和使用
    ModelViewSet里的过滤、排序、分页、序列化设置
    Django和DjangoDRF的区别
    RESTFUL风格
    MVT和MVC的个人理解
    HTTP请求简单理解
    虚拟机创建Django项目并创建APP
    python列表元素添加的几种方法以及差异总结
    python时间格式
  • 原文地址:https://www.cnblogs.com/geektcp/p/11377822.html
Copyright © 2011-2022 走看看