【Java 併發編程】 05 一個能和麪試官扯很久的 volatile 關鍵字

上一篇我們在Java內存模型中(JMM)中 Happens-before 中講到了volatile原則,對於volatile變量的寫操作會早於對其的讀操作。 volatile 意思就是可見的,常用來修飾某個共享變量,意思是當共享變量的值被修改後,會及時通知到其它線程上,其它線程就能知道當前共享變量的值已經被修改了。

volatile 關鍵字用來修飾實例變量和類變量。被 volatile 修飾後的變量可以解決併發編程可見性和有序性問題。但是不能保證原子性,且volatile 只能作用於實例或者類變量,不能修飾作用於方法。

volatile 關鍵字解決可見性問題

可見性:一個線程對變量進行了修改,另外一個線程能夠立刻讀取到此變量的最新值。

【Java 併發編程】 03 萬惡的 Bug 起源—併發編程的三大特性 一文中我們講到了,緩存一致性導致可見性問題,講到了CPU發展了,目前電腦服務器都是基於多核的,爲了均衡CPU 與內存的速度差異,提高程序運行速度,引入的CPU緩存的概念。由於每個CPU 都要自己的緩存,當某一個值被修改放回內存後,其它CPU 緩存中的值還是舊值,引發了緩存不一致的問題。此時我們設想,如果內存中的值被修改後,內存通知CPU緩存,告訴CPU緩存中的值已經失效,請重新獲取。被 volatile 關鍵字修飾的變量,就會被識別成共享變量,內存中值被修改後,各 CPU 緩存舊值失效,CPU緩存就會從內存中獲取最新的值。在這裏插入圖片描述
線程 1 和線程 2 一開始都讀取了 C 值,CPU 1 和 CPU 2 緩存中也都有了 C 值,然後線程 1 把 C 值修改了,這時候內存的值和 CPU 2 緩存中的 C 值就不等了,內存這時發現 C 值被 volatile 關鍵字修飾,發現其是共享變量,就會使 CPU 2 緩存中的 C 值狀態置爲無效,CPU 2 會從內存中重新拉取最新的值,這時候線程 2 再來讀取 C 值時,讀取的已經是內存中最新的值了。

緩存一致性協議

volatile 關鍵可以解決緩存一致性問題,保證了線程的可見性。緩存一致性協議。協議的類型很多(MSI、MESI、MOSI、Synapse、Firefly),最常見的就是Intel 的MESI 協議,它是目前主流的緩存一致性協議,此協議會保證,寫操作發生時,線程獨佔該變量的緩存,CPU 並且會通知其它線程對於該變量所在的緩存段失效。只有在獨佔操縱完成之後,該線程才能修改此變量。而此時由於其它緩存全部失效,所以就不存在緩存一致性問題。而其它線程的讀取操作,需要等寫入操作完成,恢復到共享狀態。(囉嗦了半天就一句話,寫操作在讀操作之前)

讀操作:不做任何事情,把Cache中的數據讀到寄存器。
寫操作:發出信號通知其他的CPU講改變量的Cache line置爲無效,其他的CPU要訪問共享變量的時候,只能從內存中獲取。

此圖只是擴展,不需要深入理解
其實 MESI 這個緩存一致性協議和volatile 實現內存可見性中間還差了很多抽象的東西,上面東西只是擴展,你只需要知道 volatile 修飾的共享變量是有內存可見性的就可以了。

volatile 關鍵解決有序性問題—禁止指令重排序。

有序性:代碼在運行期間保證按照編寫的順序,禁止指令重排序。

Java編譯器在生成指令序列的適當位置會插入內存屏障指令來禁止特定類型的處理器重排序,保證共享變量操作的有序性。

內存屏障: 就是在屏障前的所有指令可以重排序的,屏障之後的指令也可以重排序,但是重排序的時候不能越過內存屏障。也就是說內存屏障前的指令不會被重排序到內存屏障之後,反之亦然。

內存屏障指令:寫操作的會讓線程本地的共享內存變量寫完強制刷新到主存。讀操作讓本地線程變量無效,強制從主內存讀取,保證了共享內存變量的可見性。
JVM中提供的四類內存屏障指令
(1)LoadLoad 屏障
執行順序:Load1—>Loadload—>Load2
確保Load2及後續Load指令加載數據之前能訪問到Load1加載的數據。

(2)StoreStore 屏障
執行順序:Store1—>StoreStore—>Store2
確保Store2以及後續Store指令執行前,Store1操作的數據對其它處理器可見。

(3)LoadStore 屏障
執行順序: Load1—>LoadStore—>Store2
確保Store2和後續Store指令執行前,可以訪問到Load1加載的數據。

(4)StoreLoad 屏障
執行順序: Store1—> StoreLoad—>Load2
確保Load2和後續的Load指令讀取之前,Store1的數據對其他處理器是可見的。

對於volatile 關鍵字的認識我們還是需要時間磨合的,先了解基礎的概念,它解決了什麼問題,底層的東西我們後做了解。我還會回來的!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章