無鎖編程,即不使用鎖的狀況下實現多線程之間的變量同步,也就是在沒有線程被阻塞的狀況下實現變量的同步,因此也叫非阻塞同步(Non-blocking Synchronization)。html
實現非阻塞同步的方案稱爲「無鎖編程算法」( Non-blocking algorithm)。算法
lock-free是目前最多見的無鎖編程的實現級別(一共三種級別):編程
使用lock實現線程同步有不少缺點:安全
* 產生競爭時,線程被阻塞等待,沒法作到線程實時響應。數據結構
* dead lock。多線程
* live lock。併發
* 優先級翻轉。ide
* 使用不當,形成性能降低。oop
是最理想的模式,整個操做保證每一個線程在有限步驟下完成。性能
保證系統級吞吐(system-wide throughput)以及無線程飢餓。
截止2011年,沒有多少具體的實現。即便實現了,也須要依賴於具體CPU。
容許個別線程飢餓,但保證系統級吞吐。
確保至少有一個線程可以繼續執行。
wait-free的算法一定也是lock-free的。
在任什麼時候間點,一個線程被隔離爲一個事務進行執行(其餘線程suspended),而且在有限步驟內完成。
在執行過程當中,一旦發現數據被修改(採用時間戳、版本號),則回滾。
也叫作樂觀鎖,即樂觀併發控制(OOC)。
事務的過程是:1讀取,並寫時間戳;2準備寫入,版本校驗;3校驗經過則寫入,校驗不經過,則回滾。
CAS( compare and swap) 原子操做,用來實現多線程下的變量同步。
保證了若是須要更新的地址沒有被其餘進程(線程)改動過,那麼它能夠安全的寫入。
而這也是咱們對於某個數據或者數據結構加鎖要保護的內容,保證讀寫的一致性,不出現dirty data。
CAS原語有三個參數:
算法邏輯:
int compare_and_swap (int* reg, int oldval, int newval) { ATOMIC(); int old_reg_val = *reg; if (old_reg_val == oldval) *reg = newval; END_ATOMIC(); return old_reg_val; }
可在循環中不斷執行CAS,若是共享變量沒有改變,那麼swap,在當前環境中寫入,不然繼續do-while的Retry-Loop。
ABA問題最容易發生在lock free算法中的,地址被重用的狀況。
無鎖至關於「鎖」的粒度變小了,主要是「鎖」HEAD和TAIL這兩個關鍵資源。而不是整個數據結構。
thread1意圖對val=1進行操做變成2,cas(*val,1,2)。
thread1先讀取val=1;thread1被搶佔(preempted),讓thread2運行。
thread2 修改val=3,又修改回1。
thread1繼續執行,發現指望值與「原值」(其實被修改過了)相同,完成CAS操做。
使用CAS會形成ABA問題,特別是在使用指針操做一些併發數據結構時。
解決方案
ABAʹ:添加額外的標記用來指示是否被修改。
# Java demo AtomicInteger atom = new AtomicInteger(1); boolean r = atom.compareAndSet(1, 2); # C# demo int i=1; Interlocked.Increment(ref i);