七、真正的技術——CAS操作原理、實現、底層原始碼

Hro發表於2018-11-30

11、CAS原理與實現:

    1、定義:
	比較和交換(Conmpare And Swap,簡稱CAS)是用於實現多執行緒同步的原子指令。
	JAVA中的CAS操作都是通過sun包下Unsafe類實現,而Unsafe類中的方法都是native方,
	native方法的實現位於unsafe.cpp
	
	原始碼流程如下:
	    java中方法(以AtomicInteger為例):
		public final boolean compareAndSet(int expect, int update) {
		    return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
		}
		//物件o中offset偏移位置的值等於期望值(expected),
		//就將該offset處的值更新為x,當更新成功時,返回true,
		//native標記的方法在C++底層實現
		public final native boolean compareAndSwapInt(Object o, long offset, 
		    int expected, int x);
		
		unsafe.cpp中C++方法(compareAndSwapInt實現):
			//定義
			UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSwapInt(JNIEnv *env, 
			    jobject unsafe, jobject obj, jlong offset, jint e, jint x))
			  UnsafeWrapper("Unsafe_CompareAndSwapInt");
			  //判斷obj是否為空,返回obj指標的值
			  oop p = JNIHandles::resolve(obj);
			  //用p的地址加上offset得到具體記憶體地址
			  jint* addr = (jint *) index_oop_from_field_offset_long
			    (p, offset);
			  //通過Atomic::cmpxchg實現比較替換,其中引數x是即將更新的值,
			    引數e是原記憶體的值
			  return (jint)(Atomic::cmpxchg(x, addr, e)) == e;
			UNSAFE_END

			//內聯彙編
			inline jint Atomic::cmpxchg (jint exchange_value, 
			    volatile jint* dest, jint compare_value) {
			    int mp = os::isMP(); //判斷是否是多處理器
			    //volatile表示禁止編譯器優化
			    __asm__ volatile (
			    //根據當前系統是否為多核處理器決定是否為cmpxchg指令
			      新增lock字首
			    LOCK_IF_MP(%4) "cmpxchgl %1,(%3)"
                            : "=a" (exchange_value)
                            : "r" (exchange_value), "a" (compare_value), "r" (dest), 
                                "r" (mp)
                            : "cc", "memory");
			    }
	總結:
	    CAS操作實現:
	        用預期值A1和記憶體值A2做對比,如果A1等於A2,則記憶體值修改成B並返回true,
	        否則不操作並返回false。
	
	缺點:
	    ABA問題:多執行緒時,其餘執行緒修改記憶體值之後又還原為初始值,
	    當前執行緒比較值時,值一樣則操作成功。
	解決辦法:
	    java併發包中提供了一個帶有標記的原子引用類AtomicStampedReference,
	    通過控制變數值的版本來保證CAS的正確性。
	    
	    AtomicStampedReference以一個int值作為版本號,
	    每次更改前先取到這個int值的版本號,
	    等到修改的時候,比較當前版本號與當前執行緒持有的版本號是否一致,
	    如果一致,則進行修改,並將版本號+1。
複製程式碼

相關文章