理解volatile的保證可見性與不保證原子性

2021-09-10 08:54:05 字數 1441 閱讀 4687

cpu只對暫存器中的資料進行計算,為了加快暫存器和記憶體的資料交換,會有乙個快取區,暫存器與快取區交換速度更快。資料從快取區寫回記憶體中這個動作由系統決定。所以會存在某一資料被修改,卻沒有被立即同步到記憶體中,導致其他執行緒拿到的值是過期值。而加了volatile則相當於告訴計算機將這個值立即寫回記憶體,對其他執行緒可見。

volatile欄位可以保證執行緒拿到了最新值,即get操作是原子性的,但無法保證getandoperate操作的原子性。因為在操作過程中會存在中間狀態,這時該值可能已經過期。例如對於volatile a,a++看似只是一條語句,卻是三步:

將值a和1分別寫入暫存器

累加器計算兩個暫存器的值,寫入其中乙個暫存器

a=b將計算結果從暫存器寫回記憶體

所以在執行第二步的指令時,a的值可能已經過期,第三步將乙個基於可能過期的值得到的計算結果寫回記憶體。所以原子性無法保證。

下面用**加以體現:

private

volatile

int count =0;

@test

public

void

volatiletest()

throws interruptedexception })

; thread.

start()

;}thread.

sleep

(4000l)

; system.out.

println

(count)

;}

考慮到可能執行緒還沒執行,就已經執行了system.out.println(count),不具有說服性,所以加了休眠時間,等待其他執行緒執行完,利用countdownlatch可以更好的實現等待:

@test

public

void

volatiletest2()

throws interruptedexception })

; thread.

start()

;}done.

await()

; system.out.

println

(count)

;}

多次執行,volatiletest2()輸出值有79987,79983,79988等,可見volatile並不能保證原子性。

要想保證原子性,無論是通過鎖亦或是cas重試,都必須保證對資源的獨佔,這樣才能保證原子性。

Volatile如何保證可見性

首先要知道記憶體屏障是什麼,記憶體屏障是乙個cpu指令,記憶體屏障是這樣的指令 1,確保特定操作執行的順序 2,影響一些資料的可見性,編譯器和cpu可以保證輸出結果一樣的前提下對指令進行重排序,使得效能優化,當插入乙個記憶體屏障,相當於告訴cpu和編譯器,先於這個命令的必須先執行,後於這個命令的必須...

volatile是如何保證記憶體可見性的

volatile 修飾的變數具備兩種特性 cpu修改資料,首先是對快取的修改,然後再同步回主存,在同步回主存的時候,如果其他cpu也快取了這個資料,就會導致其他cpu快取上的資料失效 通過嗅探匯流排資料傳播,檢查快取對應的主存位址是否被修改過 這樣,當其他cpu再去它的快取讀取這個資料的時候發現快取...

volatile如何保證可見性和防止重排序

1 保證可見性 記憶體可見性是指乙個cpu對資料修改,對其他cpu立即可見。1 cpu對資料修改 cpu對資料的修改總是先修改工作記憶體,然後再同步回主記憶體,只不過是對被volatile修飾變數的修改,會立刻同步回主記憶體。2 對其他cpu立即可見 當cpu a修改完volatile變數,並且立即...