![](/img/trans.png)
[英]Java -> volatile and final: Volatile as flushing-all-memory-content
[英]Java: Make all fields either final or volatile?
如果我有一個在線程之間共享的對象,在我看來,每個字段應該是final
或volatile
,具有以下推理:
如果應該更改字段(指向另一個對象,更新原始值),則該字段應該是volatile
以便所有其他線程對新值進行操作。 僅僅訪問所述字段的方法的同步是不夠的,因為它們可能返回緩存的值。
如果該領域永遠不會改變,那就讓它成為final
。
但是,我找不到任何關於此的內容,所以我想知道這個邏輯是否有缺陷還是太明顯?
當然編輯而不是volatile可能會使用final AtomicReference
或類似的。
編輯 ,例如,請參閱get getter方法是Java中volatile的替代方法嗎?
編輯以避免混淆: 這個問題是關於緩存失效! 如果兩個線程對同一個對象進行操作,則可以緩存對象的字段(每個線程),如果它們未聲明為volatile。 如何保證緩存無效?
最后的編輯感謝@Peter Lawrey,他指出了JLS§17(Java內存模型)。 據我所知,它表明同步在操作之間建立了先發生關系,因此如果那些更新“發生在之前”,則線程會看到來自另一個線程的更新,例如,如果非易失性字段的getter和setter是synchronized
。
雖然我認為private final
應該是字段和變量的默認值,其中包含var
這樣的關鍵字使其變得可變,但是當你不需要它時使用volatile是
final
那樣通過說不應該改變它來提高清晰度,在不需要時使用volatile
,可能會讓讀者試圖弄清楚為什么它變得不穩定會讓人感到困惑。 如果應該更改字段(指向另一個對象,更新原始值),則該字段應該是volatile,以便所有其他線程對新值進行操作。
雖然這對於讀取是好的,但請考慮這個簡單的情況。
volatile int x;
x++;
這不是線程安全的。 因為它是一樣的
int x2 = x;
x2 = x2 + 1; // multiple threads could be executing on the same value at this point.
x = x2;
更糟糕的是,使用volatile
會使這種bug更難找到。
正如yshavit指出的那樣,更新多個字段更難以解決volatile
例如HashMap.put(a, b)
更新多個引用。
僅僅訪問所述字段的方法的同步是不夠的,因為它們可能返回緩存的值。
synchronized給你所有內存保證的volatile
和更多,這就是它明顯變慢的原因。
注意:只是synchronized
每個方法並不總是足夠的。 StringBuffer
使每個方法都同步,但在多線程上下文中是無用的,因為它的使用很可能容易出錯。
很容易認為實現線程安全就像灑上仙塵一樣,添加一些神奇的線程安全,你的bug就會消失。 問題是螺紋安全更像是一個有很多孔的鏟斗。 插入最大的孔並且這些漏洞看起來會消失,但除非你全部插上它們,否則你沒有線程安全,但它可能更難找到。
就同步與易失性而言,這表明了這一點
其他機制,例如volatile變量的讀寫和java.util.concurrent包中的類的使用,提供了替代的同步方法。
https://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html
無論線程問題如何,創建不需要更改final
字段都是一個好主意。 它使類的實例更容易推理,因為你可以更容易地知道它的狀態。
在使其他字段volatile
:
僅僅訪問所述字段的方法的同步是不夠的,因為它們可能返回緩存的值。
如果訪問synchronized塊之外的值,則只能看到緩存的值。
所有訪問都需要正確同步。 保證在另一個同步塊的啟動之前(在同一監視器上同步時)發生一個同步塊的結束。
至少有幾種情況你仍然需要使用同步:
Atomic*
類而不是“普通舊字段”; 但即使對於單個字段更新,您仍然可能需要獨占訪問權限(例如,將一個元素添加到列表中,同時刪除另一個元素)。 ArrayList
或數組。 如果線程之間共享一個對象,則有兩個明確的選項:
1.將該對象設為只讀
因此,更新(或緩存)沒有任何影響。
2.同步對象本身
緩存失效很難。 很難。 因此,如果您需要保證沒有陳舊的值,您應該保護該值並保護圍繞所述值的鎖定 。
在共享對象上將鎖和值設置為私有,因此這里的操作是實現細節。
為避免死鎖,此操作應為“原子”,以避免與其他任何鎖相互作用。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.