![](/img/trans.png)
[英]Understanding atomic-ness, visibility and reordering of synchonized blocks vs volatile variables in Java
[英]Lock vs synchronized vs atomic variables vs volatile in java in terms of read-write atomicity, visibility and protection from reordering
我從 Java Concurrency in Practice 一書中讀到了以下關於volatile
的內容:
當一個字段被聲明為 volatile 時,編譯器和運行時會注意到這個變量是共享的,並且對它的操作不應與其他內存操作重新排序。 易失性變量不會緩存在寄存器或緩存中,它們對其他處理器隱藏,因此對易失性變量的讀取始終返回任何線程的最新寫入。
volatile 變量的可見性影響超出了 volatile 變量本身的值。 當線程 A 寫入一個 volatile 變量,隨后線程 B 讀取同一個變量時,在寫入 volatile 變量之前對 A 可見的所有變量的值在讀取 volatile 變量后對 B 可見。 所以從內存可見性的角度來看,寫入一個 volatile 變量就像退出一個同步塊,讀取一個 volatile 變量就像進入一個同步塊。
我對上面的最后一句話感到困惑。 假設變量x
被定義為volatile
並且在修改x
、 u
、 v
和w
之前對線程A
可見,那么當線程B
之后讀取x
,它也將能夠讀取u
、 v
和w
最新值。 我們可以為synchronized
指定相同的嗎?。
一季度。 也就是說,下面正確嗎?
變量
u
、v
和w
在退出synchronized
塊時對線程A
可見,然后u
、v
和w
的最新值對之后進入synchronized
塊的線程B
可見。
我覺得上述事實是不正確的,因為u
、 v
和w
可能存儲在緩存和寄存器中,因為它們沒有被定義為volatile
。 我對此是否正確? 因此, synchronized
不能確保可見性(以及locks
和atomic
變量,因為它們類似於synchronized
)
書中進一步說:
加鎖可以同時保證可見性和原子性; volatile 變量只能保證可見性。
但我感覺如下:
synchronized
和原子變量僅保證讀寫原子性(不可見性和防止重新排序)。volatile
保證可見性並防止編譯器和運行時重新排序(不是讀寫原子性)。Q2。 以上兩點我是否正確?
1) 鎖、同步和原子變量保證讀寫原子性和可見性以及防止重新排序
2) volatile 保證可見性並防止編譯器和運行時重新排序
volatile 字段的讀寫原子性有點棘手:讀取和寫入 volatile 字段是原子的,例如,如果您在 32 位 jvm 上寫入 volatile long(64 位),則讀取和寫入仍然是原子的。 您總是閱讀完整的 64 位。 但是像 ++ 對 volatile int 或 long 的操作不是原子的
希望以下內容是准確的......這是我目前盡可能簡單但不簡單的理解......
一季度。 也就是說,下面正確嗎?
變量
u
、v
和w
在退出synchronized
塊時對線程A
可見,然后u
、v
和w
的最新值對之后進入synchronized
塊的線程B
可見。
我在這里假設“最新值”實際上是指“退出synchronized
塊時的最新值”......
然后是的 - 當然需要注意的是, A
和B
必須在同一個對象上同步。
旁注:當然,類似的警告適用於volatile
的可見性保證 - A
和B
必須(分別)寫入和讀取相同的 volatile 字段。
但我感覺如下:
- 鎖、
synchronized
和原子變量僅保證讀寫原子性(不可見性和防止重新排序)。volatile
保證可見性並防止編譯器和運行時重新排序(不是讀寫原子性)。Q2。 以上兩點我是否正確?
對#2 正確但對#1 不正確...
synchronized
保證了可見性和原子性。 “可見性”的概念也被描述為存在先發生的關系。
換句話說,線程A
退出synchronized (x)
發生在線程B
進入synchronized (x)
。
類似地,寫入volatile
字段x
發生在讀取volatile
字段x
。
換句話說,關於可見性, synchronized
進入/退出對為您提供與volatile
讀/寫對完全相同的保證。
但是synchronized
對保證可見性和原子性,而易volatile
對只保證可見性。
糟糕 - 忘記了一個例外: volatile long
和volatile double
確實保證這些 64 位值的讀取和寫入將是原子的(即,將避免“字撕裂”)。
另一種看待它的方式:有一個volatile
字段x
有點像在每次讀取或寫入x
周圍有一個微小的synchronized (x')
,其中x'
是一些與x
對應的其他不可見的鎖對象(它並不完全相同,因為使用volatile
您必須將讀取與寫入配對,而所有synchronized
關鍵字的工作方式相同)。
我覺得上述事實是不正確的,因為 u、v 和 w 可能存儲在緩存和寄存器中,因為它們沒有被定義為 volatile。 我對此是否正確?
這有點令人驚訝,但是synchronized
和volatile
提供的可見性保證適用於兩個線程可見的所有內容,而不僅限於被鎖定的對象、 volatile
字段本身、同一對象中的其他字段等.
這就是為什么如果您熟悉低級匯編/內核編程等,從內存屏障的角度考慮它們是有意義的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.