簡體   English   中英

Java和C#中的volatile語義背后的原因是什么?

[英]what is the reasoning behind volatile semantics in Java and C#

C#和Java都定義了這一點
* volatile讀取具有獲取語義
* volatile寫入具有發布語義

我的問題是:

  1. 這是定義volatile的唯一正確方法嗎?
  2. 如果沒有,如果語義被顛倒,事情就會大不相同,也就是說
    • volatile讀取具有釋放語義
    • volatile寫入具有獲取語義

volatile語義背后的原因源於Java內存模型 ,它是根據操作指定的:

  • 讀取和寫入變量
  • 鎖定和解鎖顯示器
  • 開始和加入線程

Java內存模型為Java程序中可能發生的操作定義了一個名為happen-before部分排序 通常無法保證線程可以看到每個其他操作的結果。

假設你有兩個動作AB. 為了保證執行動作B的線程可以看到動作A的結果,A和B之間必須存在先發生關系。否則,JVM可以隨意對它們進行重新排序

未正確同步的程序可能會有數據爭用。 當一個變量被> 1個線程讀取並由> = 1個線程寫入時,會發生數據爭用,但讀取和寫入操作不是通過先前發生的順序排序的。

因此,正確同步的程序沒有數據爭用,程序內的所有操作都按固定順序發生。

所以行動通常只是部分訂購,但也有一個訂單:

  • 鎖定獲取和釋放
  • 讀取和寫入volatile變量

這些行動是完全有序的。

這使得在“后續”鎖定獲取和易失性變量讀取方面描述發生之前是明智的。

關於你的問題:

  1. 通過之前發生的關系,您可以使用volatile的替代定義
  2. 顛倒順序對上面的定義沒有意義,特別是因為涉及總訂單。

之前發生

這說明了當兩個線程使用公共同步時發生在之前的關系。 線程A中的所有操作都按程序順序規則排序 ,線程B中的操作也是如此。因為A釋放鎖定M而B 隨后獲取M,因此在釋放鎖定之前A中的所有操作都在B中的操作之前排序獲得鎖定后。 當兩個線程在不同的鎖上同步時,我們不能說它們之間的動作順序,在兩個線程中的動作之間沒有發生 - 之前的關系。

來源: 實踐中的Java並發

獲取/釋放語義的強大之處不在於其他線程多久能夠看到易失性字段本身的新寫入值,而在於易失性操作在不同線程之間建立先發生關系的方式。 如果線程A讀取volatile字段並且看到在另一個線程B中寫入該字段的值,那么線程A也保證在線程B執行之前看到線程B寫入其他 (不一定是易失性)變量的值。易失寫。 這看起來像緩存刷新,但僅從讀取volatile的線程的角度來看,其他不接觸volatile字段的線程沒有關於B的排序保證,並且可能會看到一些早期的非易失性寫入但是如果編譯器/ JIT如此傾向,則不是其他人。

監視器獲取/釋放的特征類似於它們引發的先發生關系 - 在監視器釋放之前,一個線程的動作保證在另一個線程后續獲取同一監視器之后可見。 Volatiles為您提供與監視器同步相同的排序保證,但不會阻塞。

暫無
暫無

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

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