zoukankan      html  css  js  c++  java
  • Java cas原理

    JDK concurrent包下有很多原子类AtomicInteger.java等,提供了原子更新操作。

    下面是一个cas demo的方法

    public static void casDemo(){
            AtomicInteger atomicInteger = new AtomicInteger(1);
            int x = atomicInteger.getAndIncrement();
            System.out.println("x = " + x);
        }

    这里getAndIncrement会自赠1,并且是线程安全的。

    跟进JDK源码

    AtomicInteger.getAndIncrement()方法

    /**
         * Atomically increments the current value,
         * with memory effects as specified by {@link VarHandle#getAndAdd}.
         *
         * <p>Equivalent to {@code getAndAdd(1)}.
         *
         * @return the previous value
         */
        public final int getAndIncrement() {
            return U.getAndAddInt(this, VALUE, 1);
        }

    注释可以看出方法的作用是原子更新变量,继续跟进U.getAndAddInt()方法

    /**
         * Atomically adds the given value to the current value of a field
         * or array element within the given object {@code o}
         * at the given {@code offset}.
         *
         * @param o object/array to update the field/element in
         * @param offset field/element offset
         * @param delta the value to add
         * @return the previous value
         * @since 1.8
         */
        @HotSpotIntrinsicCandidate
        public final int getAndAddInt(Object o, long offset, int delta) {
            int v;
            do {
                v = getIntVolatile(o, offset);
            } while (!weakCompareAndSetInt(o, offset, v, v + delta));
            return v;
        }

    这里我用的JDK 10可能会有点不一样,继续跟进weakCompareAndSetnt()方法

    @HotSpotIntrinsicCandidate
        public final boolean weakCompareAndSetInt(Object o, long offset,
                                                  int expected,
                                                  int x) {
            return compareAndSetInt(o, offset, expected, x);
        }

    继续跟进compareAndSetInt()方法

    /**
         * Atomically updates Java variable to {@code x} if it is currently
         * holding {@code expected}.
         *
         * <p>This operation has memory semantics of a {@code volatile} read
         * and write.  Corresponds to C11 atomic_compare_exchange_strong.
         *
         * @return {@code true} if successful
         */
        @HotSpotIntrinsicCandidate
        public final native boolean compareAndSetInt(Object o, long offset,
                                                     int expected,
                                                     int x);

    这里是一个native方法,native方法,即本地方法,调用其他语言实现的方法。openjdk可以看出jvm主要是c++实现,网上看到别人贴出来openjdk源码

    // Adding a lock prefix to an instruction on MP machine
    // VC++ doesn't like the lock prefix to be on a single line
    // so we can't insert a label after the lock prefix.
    // By emitting a lock prefix, we can define a label after it.
    #define LOCK_IF_MP(mp) __asm cmp mp, 0  
                           __asm je L0      
                           __asm _emit 0xF0 
                           __asm L0:
    
    inline jint     Atomic::cmpxchg    (jint     exchange_value, volatile jint*     dest, jint     compare_value) {
      // alternative for InterlockedCompareExchange
      int mp = os::is_MP();
      __asm {
        mov edx, dest
        mov ecx, exchange_value
        mov eax, compare_value
        LOCK_IF_MP(mp)
        cmpxchg dword ptr [edx], ecx
      }
    }

    这段源码可以看到用了汇编的cmpxchg指令,这个在多cpu情况下会在指令前加lock前缀,保证指令执行的原子性。单核cpu不会加lock前缀。

    这条指令如何保证原子性,就是cpu的事情了,网上有资料说是锁住总线、锁住共享内存等

    cas优点:

    1. 不用阻塞线程,不会进行线程上下文切换

    缺点:

    1. 线程自旋, cpu空转

    2. 不能保证多个变量的原子性

    3. 不能感知到ABA问题,可以考虑使用版本号解决

    参考

    1. http://zl198751.iteye.com/blog/1848575

    2. https://blog.csdn.net/xiuye2015/article/details/53406432

  • 相关阅读:
    hdu--4027--不错的线段树
    hdu--3275--线段树<again>
    hdu--2795--又是线段树
    hdu--4407--一不留神就TLE了
    zoj--3822--第二题概率dp
    hdu--3911--线段树<我最近爱上她了>
    hdu--1710--二叉树的各种遍历间的联系
    hdu--1712--分组背包<如果你真的明白了背包..>
    hdu--4576--概率dp<见过最简单的概率dp>
    list remove object
  • 原文地址:https://www.cnblogs.com/luckygxf/p/9000782.html
Copyright © 2011-2022 走看看