關於併發編程CAS算法和AQS框架的理解

在併發編程中咱們最經常使用到的兩塊:一種是基於CAS 機制實現的Atomic類操做,一種是基於AQS實現的同步類實現如經常使用的ReentrantLock/Semaphore/CountDownLatch等;html

CAS:編程

CAS是英文單詞Compare and Swap的縮寫,翻譯過來就是比較並替換。多線程

CAS機制中使用了3個基本操做數:內存地址V,舊的預期值A,要修改的新值B。併發

更新一個變量的時候,只有當變量的預期值A和內存地址V當中的實際值相同時,纔會將內存地址V對應的值修改成B。函數

從思想上來講,synchronized屬於悲觀鎖,悲觀的認爲程序中的併發狀況嚴重,因此嚴防死守,CAS屬於樂觀鎖,樂觀地認爲程序中的併發狀況不那麼嚴重,因此讓線程不斷去重試更新。ui

CAS的缺點:線程

1) CPU開銷過大翻譯

在併發量比較高的狀況下,若是許多線程反覆嘗試更新某一個變量,卻又一直更新不成功,循環往復,會給CPU帶來很到的壓力。htm

2) 不能保證代碼塊的原子性blog

CAS機制所保證的知識一個變量的原子性操做,而不能保證整個代碼塊的原子性。好比須要保證3個變量共同進行原子性的更新,就不得不使用synchronized了。

3) ABA問題

這是CAS機制最大的問題所在。(能夠經過版本號解決)

AQS:

它維護了一個volatile int state(表明共享資源)和一個FIFO線程等待隊列(多線程爭用資源被阻塞時會進入此隊列);

以ReentrantLock爲例,state初始化爲0,表示未鎖定狀態。A線程lock()時,會調用tryAcquire()獨佔該鎖並將state+1。此後,其餘線程再tryAcquire()時就會失敗,直到A線程unlock()到state=0(即釋放鎖)爲止,其它線程纔有機會獲取該鎖。固然,釋放鎖以前,A線程本身是能夠重複獲取此鎖的(state會累加),這就是可重入的概念。但要注意,獲取多少次就要釋放多麼次,這樣才能保證state是能回到零態的。好比lock兩次,就必須unlock兩次;

再以CountDownLatch以例,任務分爲N個子線程去執行,state也初始化爲N(注意N要與線程個數一致)。這N個子線程是並行執行的,每一個子線程執行完後countDown()一次,state會CAS減1。等到全部子線程都執行完後(即state=0),會unpark()主調用線程,而後主調用線程就會從await()函數返回,繼續後餘動做。

參考:http://www.javashuo.com/article/p-xcevmtwv-gz.html

相關文章
相關標籤/搜索