Java核心知識 多線程併發 volatile 關鍵字的作用(二十六)

Java 語言提供了一種稍弱的同步機制,即 volatile 變量,用來確保將變量的更新操作通知到其他 線程。volatile 變量具備兩種特性,volatile 變量不會被緩存在寄存器或者對其他處理器不可見的 地方,因此在讀取 volatile 類型的變量時總會返回最新寫入的值。

變量可見性

其一是保證該變量對所有線程可見,這裡的可見性指的是當一個線程修改了變量的值,那麼新的 值對於其他線程是可以立即獲取的。

禁止重排序

volatile 禁止了指令重排。

比 sychronized 更輕量級的同步鎖

在訪問 volatile 變量時不會執行加鎖操作,因此也就不會使執行線程阻塞,因此 volatile 變量是一 種比 sychronized 關鍵字更輕量級的同步機制。volatile 適合這種場景:一個變量被多個線程共 享,線程直接給這個變量賦值。


當對非 volatile 變量進行讀寫的時候,每個線程先從內存拷貝變量到 CPU 緩存中。如果計算機有 多個 CPU,每個線程可能在不同的 CPU 上被處理,這意味著每個線程可以拷貝到不同的 CPU cache 中。而聲明變量是 volatile 的,JVM 保證了每次讀變量都從內存中讀,跳過 CPU cache 這一步。

適用場景

值得說明的是對 volatile 變量的單次讀/寫操作可以保證原子性的,如 long 和 double 類型變量, 但是並不能保證 i++這種操作的原子性,因為本質上 i++是讀、寫兩次操作。在某些場景下可以 代替 Synchronized。但是,volatile 的不能完全取代 Synchronized 的位置,只有在一些特殊的場景下,才能適用 volatile。總的來說,必須同時滿足下面兩個條件才能保證在併發環境的線程安 全:

(1)對變量的寫操作不依賴於當前值(比如 i++),或者說是單純的變量賦值(boolean flag = true)。

(2)該變量沒有包含在具有其他變量的不變式中,也就是說,不同的 volatile 變量之間,不 能互相依賴。只有在狀態真正獨立於程序內其他內容時才能使用 volatile。