11.25 面試問到:volatile變量適合於什麼場景下應用,如何回答

要想知道在什麼場景下用首先需要知道volatile是什麼,它表示可見性,是指線程之間的可見性,一個線程修改的狀態對另一個線程是可見的

也就是一個線程修改的結果。另一個線程馬上就能看到。

為什麼說一個線程修改後結果另外一個線程是可見的,因為volatile修飾的變量不允許線程內部緩存和重排序,即直接修改內存。所以對其他線程是可見的,但是這裡需要注意:volatile修飾內容具有可見性,但不能保證它具有原子性。比如我們對i進行加1操作

面試問到:volatile變量適合於什麼場景下應用,如何回答

加1操作

多線程同時進行加1操作,發現值為4,所以不能保證原子性,切記。為什麼這個值不對,大家都知道java是值傳遞,JVM在運行時內存分配彙總有一個內存區域稱為虛擬機棧, 線程棧保存了線程運行時的信息,當線程訪問某個對象的值的時候,首先通過對象的引用找到對應在堆內存的變量的值,然後把堆內存變量的值load到本地內存中(當前線程所分配內存區域),建立一個變量副本, 之後線程不再和對象在堆內存的變量有任何聯繫,而是直接修改副本的值,在修改完成之後自動把變量副本寫回堆內存,這樣堆內存的值就會改變,如果線程1對該volatile變量修改還未結束, 線程2也進行修改, 但修改的是最初的值, 將會導致併發的發生。

然而他也可以說是一種稍弱的同步機制,用來確保變量的更新操作通知到其他線程。當把變量聲明為volatile類型後,編譯器和運行時都會注意到這個變量是共享的,因此不會將該變量上的操作與其他內存操作一起重排序。volatile變量不會被緩存在寄存器或者對其他處理器不可見的地方,因此在讀取volatile類型的變量時總會返回最新寫入的值。在訪問volatile變量時不會執行加鎖操作,因此也就不會使執行線程阻塞,因此volatile變量是一種比sychronized關鍵字更輕量級的同步機制。這裡深入一點說就是內存屏障,內存屏障(memory barrier)是一個CPU指令。基本上,它是這樣一條指令:

  • 確保一些特定操作執行的順序;
  • 影響一些數據的可見性(可能是某些指令執行後的結果)。

編譯器和CPU可以在保證輸出結果一樣的情況下對指令重排序,使性能得到優化。插入一個內存屏障,相當於告訴CPU和編譯器先於這個命令的必須先執行,後於這個命令的必須後執行。內存屏障另一個作用是強制更新一次不同CPU的緩存。例如,一個寫屏障會把這個屏障前寫入的數據刷新到緩存,這樣任何試圖讀取該數據的線程將得到最新值,而不用考慮到底是被哪個cpu核心或者哪個CPU執行的。

這裡必須要懂得:1、一旦你完成寫入,任何訪問這個字段的線程將會得到最新的值。2、在你寫入前,會保證所有之前發生的事已經發生,並且任何更新過的數據值也是可見的,因為內存屏障會把之前的寫入值都刷新到緩存。

綜上所述我們在實際開發中:

  1. 對變量的寫入不依賴變量當前的值, 或者能確保只有單線程更新變量的值
  2. 該變量不會與其他狀態變量一起納入不變性條件中
  3. 在訪問變量時不需要加鎖


分享到:


相關文章: