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

posted on 2018-05-07 07:19  luckygxf  阅读(277)  评论(0编辑  收藏  举报

导航