簡體   English   中英

在讀寫原子性、可見性和防止重新排序方面,鎖定、同步、原子變量與 Java 中的 volatile

[英]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並且在修改xuvw之前對線程A可見,那么當線程B之后讀取x ,它也將能夠讀取uvw最新值。 我們可以為synchronized指定相同的嗎?。

一季度。 也就是說,下面正確嗎?

變量uvw在退出synchronized塊時對線程A可見,然后uvw的最新值對之后進入synchronized塊的線程B可見。

我覺得上述事實是不正確的,因為uvw可能存儲在緩存和寄存器中,因為它們沒有被定義為volatile 我對此是否正確? 因此, synchronized不能確保可見性(以及locksatomic變量,因為它們類似於synchronized

書中進一步說:

加鎖可以同時保證可見性和原子性; volatile 變量只能保證可見性。

但我感覺如下:

  1. 鎖、 synchronized和原子變量僅保證讀寫原子性(不可見性和防止重新排序)。
  2. volatile保證可見性並防止編譯器和運行時重新排序(不是讀寫原子性)。

Q2。 以上兩點我是否正確?

1) 鎖、同步和原子變量保證讀寫原子性可見性以及防止重新排序

2) volatile 保證可見性並防止編譯器和運行時重新排序

volatile 字段的讀寫原子性有點棘手:讀取和寫入 volatile 字段是原子的,例如,如果您在 32 位 jvm 上寫入 volatile long(64 位),則讀取和寫入仍然是原子的。 您總是閱讀完整的 64 位。 但是像 ++ 對 volatile int 或 long 的操作不是原子的

希望以下內容是准確的......這是我目前盡可能簡單但不簡單的理解......

一季度。 也就是說,下面正確嗎?

變量uvw在退出synchronized塊時對線程A可見,然后uvw的最新值對之后進入synchronized塊的線程B可見。

我在這里假設“最新值”實際上是指“退出synchronized塊時的最新值”......

然后是的 - 當然需要注意的是, AB必須在同一個對象上同步。

旁注:當然,類似的警告適用於volatile的可見性保證 - AB必須(分別)寫入和讀取相同的 volatile 字段

但我感覺如下:

  1. 鎖、 synchronized和原子變量僅保證讀寫原子性(不可見性和防止重新排序)。
  2. volatile保證可見性並防止編譯器和運行時重新排序(不是讀寫原子性)。

Q2。 以上兩點我是否正確?

對#2 正確但對#1 不正確...

synchronized保證了可見性和原子性。 “可見性”的概念也被描述為存在先發生的關系。

換句話說,線程A退出synchronized (x)發生在線程B進入synchronized (x)

類似地,寫入volatile字段x發生在讀取volatile字段x

換句話說,關於可見性synchronized進入/退出對為您提供與volatile讀/寫對完全相同的保證。

但是synchronized對保證可見性和原子性,而易volatile對只保證可見性。

糟糕 - 忘記了一個例外: volatile longvolatile double確實保證這些 64 位值的讀取和寫入將是原子的(即,將避免“字撕裂”)。

另一種看待它的方式:有一個volatile字段x有點像在每次讀取或寫入x周圍有一個微小的synchronized (x') ,其中x'是一些與x對應的其他不可見的鎖對象(它並不完全相同,因為使用volatile您必須將讀取與寫入配對,而所有synchronized關鍵字的工作方式相同)。

我覺得上述事實是不正確的,因為 u、v 和 w 可能存儲在緩存和寄存器中,因為它們沒有被定義為 volatile。 我對此是否正確?

這有點令人驚訝,但是synchronizedvolatile提供的可見性保證適用於兩個線程可見的所有內容,而不僅限於被鎖定的對象、 volatile字段本身、同一對象中的其他字段等.

這就是為什么如果您熟悉低級匯編/內核編程等,從內存屏障的角度考慮它們是有意義的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM