併發編程5.CAS

什麼是CAS

compare and swap

CAS的方式對屬性private int value = 0; 進行遞增操作

  1. 讀取 value 的值
  2. 將其賦值給臨時變量 a,此時 a = 0;
  3. a中獲取值進行計算,將所得結果賦值給變量b,此時 a = 0; b =1;
  4. 重新讀取value的值,與a進行比較
  5. 如果兩個值相等,則將b中的值寫入到value
  6. 如果不相等,則從頭開始讀取value的,賦值給a,計算,再進行讀取比較,直到賦值成功爲止!
比較相等
比較不相等
讀取 value 的值
將值賦值給 a
進行結算將結果賦值給 b
讀取 value 的值與 b的值進行比較
將b的值寫入到 value

源碼

AtomicInteger 爲例,追溯其incrementAndGet 的邏輯

AtomicInteger counter = new AtomicInteger();
counter.incrementAndGet();

incrementAndGet 方法中

public final int incrementAndGet() {
    return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}

incrementAndGet 方法先increment 然後 get
調用了sun.misc.Unsafe類的 getAndAddInt 方法,而裏面調用的是 getAndAddInt ,是先get然後再add,所以這裏需要加1

getAndAddInt

public final int getAndAddInt(Object o, long offset, int delta) {
    int v;
    do {
        v = getIntVolatile(o, offset);
    } while (!compareAndSwapInt(o, offset, v, v + delta));
    return v;
}

調用 compareAndSwapInt 方法,而此方法是一個native方法,因此我們需要從hotspot源碼src/share/vm/prims/unsafe.cpp 中的實現

UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSwapInt(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jint e, jint x))
  UnsafeWrapper("Unsafe_CompareAndSwapInt");
  oop p = JNIHandles::resolve(obj);
  jint* addr = (jint *) index_oop_from_field_offset_long(p, offset);
  return (jint)(Atomic::cmpxchg(x, addr, e)) == e;
UNSAFE_END

這裏調用了Atomiccmpxchg 方法,在src/os_cpu/linux_x86/vm/atomic_linux_x86.inline.hpp

inline jint     Atomic::cmpxchg    (jint     exchange_value, volatile jint*     dest, jint     compare_value) {
  int mp = os::is_MP();
  __asm__ volatile (LOCK_IF_MP(%4) "cmpxchgl %1,(%3)"
                    : "=a" (exchange_value)
                    : "r" (exchange_value), "a" (compare_value), "r" (dest), "r" (mp)
                    : "cc", "memory");
  return exchange_value;
}

這裏調用了彙編中的cmpxchgl 指令

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章