原理
編譯時,在對volatile變量的賦值操做指令後加個加鎖的空操做了強制把修改當即寫回主內存,同時其餘工做內存往執行引擎中傳遞被volatile修飾的變量的值時,必須從主內存中獲取而後馬上傳給工做引擎,這樣保證讀取到的是最新值,即爲內存可見性,另外修改同步回內存,意味着全部以前的操做都已經執行完成,這樣便造成了「指令重排序沒法越過內存屏障」的效果了。性能
做用
- 內存可見性
- volatile變量對全部線程是當即可見的,對volatile變量全部的寫操做都能馬上反應到其餘線程之中,只保證了可見性
- 但同一時間都對該值作了修改的話仍是會衝突,也就是說其餘線程的修改還來不及在你的操做執行以前通知到你的話,那麼修改就會衝突
- 所以只適用於:
- 運算結果並不依賴變量的當前值,或者可以確保只有單一的線程修改變量的值。
- 變量不須要與其餘的狀態變量共同參與不變約束。
- 即全部操做的順序能夠打亂,結果仍同樣。
- 所以,我以爲volatile修飾的變量只保證讀一致性,每個讀操做在讀時所讀到的值確保是最新值,但寫就不必定了,若是同時修改且寫回主內存時來不及通知其餘線程而其餘線程的修改也到了主內存,這時便產生了衝突。但volatile的鎖是最輕量的,它只在編譯時,在對volatile修飾的變量賦值的指令後加個加鎖的空操做而不是對該值加鎖,那麼該變量能夠任意讀取,且讀取到的數據都爲最新值,只需忍受同時修改時可能會發生的衝突,有些狀況下很值得。
- 例如若是兩條線程要作的操做一樣是把原值加上某值,而後剛好同時執行,由於加鎖的空操做都立馬寫回主內存,這是就會產生寫衝突,但若是是其中一個線程先執行該指令,以後會立馬寫回主內存,而後另外一條線程執行到該語句,而後去主內存中取值立馬交給執行引擎執行,這是就是最新的值卻不會產生寫衝突。而若是兩個線程要作的操做都是把false設置成true,而後由於可見性,其餘等待在該狀態上的線程會至關於立馬獲得通知。因此若是隻須要讀一致性,能夠忍受可能發生的寫衝突的話,volatile能夠提供比同步關鍵字更好的性能,由於這個能夠隨便讀且讀到的值是最新的值。
- 禁止指令重排序
- 指令重排序是編譯優化的技術一種,例如在條件容許的狀況下,直接運行當前有能力當即執行的後續指令,避開獲取下一條指令所需數據時形成的等待,但它只保證重排序後線程內表現爲串行的語義,即重排序後若是是單線程執行,那麼結果必定跟排序前同樣。因此重排序後,並行時會發生不少咱們以前沒法想象的問題。
- 指令重排序的規則之一是有依賴的語句之間的相對順序必須獲得保證,不然語義會出現錯誤,而後其餘的語句能夠自由插入它們之間。加鎖的空操做使得修改當即寫回主內存,這使得以前所作的操做都已經執行完成,爲了達到storeload屏障,後面的指令沒法重排序到該加鎖空操做以前,所以該加鎖空操做就像個內存屏障。