天天看點

從彙編角度了解CAS機制+淺析ABA問題

✨CAS全稱"Compare And Swap",也就是"比較并替換";它涉及三個操作數:記憶體值、預期值、新值。隻有當記憶體值和預期值一緻時,才能将記憶體值修改為新值。

從彙編角度了解CAS機制+淺析ABA問題

📚CAS操作具有原子性,它的原子性由CPU硬體指令來保證;在Java的Unsafe.class定義了大量的原子操作。以CompareAndSwapInt()方法為例,分析彙編的實作。

從彙編角度了解CAS機制+淺析ABA問題

找到HotSpot的Unsafe.cpp檔案,/src/share/vm/prims/Unsafe.cpp,最終會調用到下面這個方法

/**
 *  jobject obj : 共享變量所在的對象
 * offset:偏移量,也就是對象的大小
 * e :預期值
 * x : 新值
 * 
 */
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;      

最終會調用到src/os_cpu/atomic_linux_x86.inline.hpp(我以x86架構為例)

#define LOCK_IF_MP(mp)"cmp $0, " #mp"; je 1f; lock; 1: " //如果是多核CPU,會将lock傳回
inline jint     Atomic::cmpxchg    (jint     exchange_value, volatile jint*     dest, jint     compare_value) {
  int mp = os::is_MP();    //判斷是否是多核CPU
  __asm__ volatile (LOCK_IF_MP(%4) "cmpxchgl %1,(%3)"       //%1:交換值 (exchange_value), %3:比較值(compare_value)
                    : "=a" (exchange_value)
                    : "r" (exchange_value), "a" (compare_value), "r" (dest), "r" (mp)
                    : "cc", "memory");
  return exchange_value;    //傳回交換值
}      

lock字首指令是核心,帶lock字首的指令在執行期間會鎖住整個總線,使得其他線程無法通過總線通路主記憶體;後續科學家們對其進行了優化,如果攜帶lock字首指令執行期間能夠命中緩存,且通路的記憶體值包含在一個緩存行(64位元組),則緩存行将被鎖定,其他線程就無法通路。

🔔(1) 鎖定緩存行(如果緩存命中,且記憶體值小于一個緩存行大小(64位元組)

🔔(2) 鎖定總線

❓ABA問題是什麼?

A線程在執行過程中,B線程快速的操作變量之後又将其值進行了還原。導緻這個過程對于B線程是不可見的。