volatile 變量使用條件--終於有人講明白這兩個條件了


聲明

本文轉自volatile 變量使用條件

參考網頁

https://www.ibm.com/developerworks/cn/java/j-jtp06197.html

使用volatile的條件

volatile 變量可以被看作是一種 “程度較輕的 synchronized”;與 synchronized 塊相比,volatile 變量所需的編碼較少,並且運行時開銷也較少,但是它所能實現的功能也僅是 synchronized 的一部分。

只能在有限的一些情形下使用 volatile 變量替代鎖。要使 volatile 變量提供理想的線程安全,必須同時滿足下面兩個條件:

對變量的寫操作不依賴於當前值。

該變量沒有包含在具有其他變量的不變式中。

實際上,這些條件表明,可以被寫入 volatile 變量的這些有效值獨立於任何程序的狀態,包括變量的當前狀態。

對變量的寫操作不依賴於當前值--啥意思?

就是如果變量a定義為volatile變量,做諸如

a++;

a = a + 2;

a = 6 * a;

a = a * a;

這些操作,在多線程場景下會出現共享變量不一致的情形。

原因就是volatile無法保證原子性。如果指令執行到中間被打斷,就會出現共享變量不一致的情形。

例子

可以見

https://my.oschina.net/u/3866531/blog/1936097

其中的Test.java,int類型的變量inc被volatile修飾(inc為共享變量),但是多線程場景下inc的自增操作出現了問題。原因很簡單,volatile保證不了操作的原子性。

進一步說明

這個條件的限制使 volatile 變量不能用作線程安全計數器。雖然增量操作(x++)看上去類似一個單獨操作,實際上它是一個由讀取-修改-寫入操作序列組成的組合操作,必須以原子方式執行,而 volatile 不能提供必須的原子特性。實現正確的操作需要使 x 的值在操作期間保持不變,而 volatile 變量無法實現這點。(然而,如果將值調整為只從單個線程寫入,那么可以忽略第一個條件。)

該變量沒有包含在具有其他變量的不變式中--啥意思?

例子代碼

@NotThreadSafe

public class NumberRange { private int lower, upper; public int getLower() { return lower; } public int getUpper() { return upper; } public void setLower(int value) { if (value > upper) throw new IllegalArgumentException(...); lower = value; } public void setUpper(int value) { if (value < lower) throw new IllegalArgumentException(...); upper = value; } }

代碼解釋

代碼顯示了一個非線程安全的數值范圍類。它包含了一個不變式 —— 下界總是小於或等於上界。

這種方式限制了范圍的狀態變量,因此將 lower 和 upper 字段定義為 volatile 類型不能夠充分實現類的線程安全;從而仍然需要使用同步。否則,如果湊巧兩個線程在同一時間使用不一致的值執行 setLower 和 setUpper 的話,則會使范圍處於不一致的狀態。例如,如果初始狀態是 (0, 5),同一時間內,線程 A 調用 setLower(4) 並且線程 B 調用 setUpper(3),顯然這兩個操作交叉存入的值是不符合條件的,那么兩個線程都會通過用於保護不變式的檢查,使得最后的范圍值是 (4, 3) —— 一個無效值。至於針對范圍的其他操作,我們需要使 setLower() 和 setUpper() 操作原子化 —— 而將字段定義為 volatile 類型是無法實現這一目的的。

通俗的說

多線程場景下,【變量做依賴於自己的值的操作】,【變量包含在另一個變量的不變式中】,這兩種情況下即使使用volatile修飾變量,同步操作仍然會出現問題

感謝

https://my.oschina.net/u/3866531/blog/1939070(volatile 變量使用條件)

https://my.oschina.net/u/3866531/blog/1936097(volatile保證原子性嗎)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM