【CAS機制】
指的是CompareAndSwap或CompareAndSet,是一個原子操作,實現此機制的原子類記錄着當前值的在內存中存儲的偏移地址,將內存中的真實值V與舊的預期值A做比較,如果不一致則說明內存中的值被其他線程修改過了,返回false,否則將新值B存入內存。
Java內部是使用本地調用類unsafe實現的。
Java原子類底層原理就是采用CAS機制。
可能會出現什么問題
- aba問題:
線程1取出A之后被阻塞了,此時線程2把內存中A改為B,一系列操作后又改為A,此時線程1恢復執行,取內存中的A與手中的A做比較,發現沒有變,繼續執行。
然而此時倆A雖然可能是一樣的,但是其實是被修改過的。例如,線程1需要替換的是一個棧頂,從A替換成B,但是執行前線程2搶占到時間片,對棧做出了一系列出棧操作,然后又將A入棧,此時線程1恢復,發現棧頂還是A,所以替換成B,但此時這個棧已經不是原來的棧了。
解決思路——版本號:
在比較的時候加入版本號的比較,每次修改時也修改版本號。
1.5開始的AtomicStampedReference就是采用了的版本號比較。
- 執行開銷大:
CAS如果長時間不成功會一直自旋循環,會產生不少的執行開銷。並且為了自旋結束時避免內存順序沖突,CPU會對流水線進行重排,這樣會嚴重影響cpu性能。
解決思路——pause指令:
pause指令能讓自旋失敗時cpu睡眠一小段時間再繼續自旋,從而使得讀操作的頻率低很多,為解決內存順序沖突而導致的流水線重排的代價也會小很多。
內存順序沖突——當自旋鎖快要釋放的時候,持鎖線程會有一個store命令,外面自旋的線程會發出各自的load命令,而此處並沒任何 happen-before 排序,所以處理器是亂序執行,所以為了避免load出現在store之前此時會進行流水線清空再重排序,會嚴重影響cpu效率,Pause指令的作用就是減少並行load的數量,從而減少重排序時所耗時間。(不懂load和store可以去看看JMM(java內存模型)的資料)
- 只能保證一個共享變量的原子性操作:
解決思路——1.5開始的AtomicReference可以保證引用的原子性,可以把多變量放入對象中進行原子操作。
從自己word筆記中復制過來的,沒圖,而且格式很多有問題,有時間再補。