詳解java中CAS機制所導致的問題以及解決——內存順序沖突


CAS機制

指的是CompareAndSwap或CompareAndSet,是一個原子操作,實現此機制的原子類記錄着當前值的在內存中存儲的偏移地址,將內存中的真實值V與舊的預期值A做比較,如果不一致則說明內存中的值被其他線程修改過了,返回false,否則將新值B存入內存。

Java內部是使用本地調用類unsafe實現的。

Java原子類底層原理就是采用CAS機制。

可能會出現什么問題

  1. aba問題:

線程1取出A之后被阻塞了,此時線程2把內存中A改為B,一系列操作后又改為A,此時線程1恢復執行,取內存中的A與手中的A做比較,發現沒有變,繼續執行。

然而此時倆A雖然可能是一樣的,但是其實是被修改過的。例如,線程1需要替換的是一個棧頂,從A替換成B,但是執行前線程2搶占到時間片,對棧做出了一系列出棧操作,然后又將A入棧,此時線程1恢復,發現棧頂還是A,所以替換成B,但此時這個棧已經不是原來的棧了。

解決思路——版本號:

在比較的時候加入版本號的比較,每次修改時也修改版本號。

1.5開始的AtomicStampedReference就是采用了的版本號比較。

  1. 執行開銷大:

CAS如果長時間不成功會一直自旋循環,會產生不少的執行開銷。並且為了自旋結束時避免內存順序沖突,CPU會對流水線進行重排,這樣會嚴重影響cpu性能。

解決思路——pause指令:

pause指令能讓自旋失敗時cpu睡眠一小段時間再繼續自旋,從而使得讀操作的頻率低很多,為解決內存順序沖突而導致的流水線重排的代價也會小很多。 

內存順序沖突——當自旋鎖快要釋放的時候,持鎖線程會有一個store命令,外面自旋的線程會發出各自的load命令,而此處並沒任何 happen-before 排序,所以處理器是亂序執行,所以為了避免load出現在store之前此時會進行流水線清空再重排序,會嚴重影響cpu效率,Pause指令的作用就是減少並行load的數量,從而減少重排序時所耗時間。(不懂load和store可以去看看JMM(java內存模型)的資料)

  1. 只能保證一個共享變量的原子性操作:

解決思路——1.5開始的AtomicReference可以保證引用的原子性,可以把多變量放入對象中進行原子操作。

 

從自己word筆記中復制過來的,沒圖,而且格式很多有問題,有時間再補。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM