Java cas principle

There are many atomic classes AtomicInteger.java under the JDK concurrent package, which provide atomic update operations.

The following is a cas demo method

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

Here getAndIncrement will give 1 by itself and is thread-safe.

Follow up JDK source code

AtomicInteger.getAndIncrement() method

/**
     * 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);
    }

The annotation shows that the function of the method is to atomically update the variable, and continue to follow the U.getAndAddInt() method

/**
     * 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;
        to {
            v = getIntVolatile (o, offset);
        } while (!weakCompareAndSetInt(o, offset, v, v + delta));
        return v;
    }

The JDK 10 I use here may be a little different, continue to follow the weakCompareAndSetnt() method

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

Continue to follow up the compareAndSetInt() method

/**
     * 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);

Here is a native method, a native method, that is, a native method, that calls methods implemented in other languages. It can be seen from openjdk that jvm is mainly implemented by C++. I saw others posted the openjdk source code on the Internet.

// 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 ​​is 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. Can't perceive the ABA problem, you can consider using the version number to solve it

 

refer to

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

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

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325615620&siteId=291194637