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

CAS機制

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

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

Java原子類底層原理就是採用CAS機制。性能

可能會出現什麼問題spa

  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筆記中複製過來的,沒圖,並且格式不少有問題,有時間再補。

相關文章
相關標籤/搜索