簡體   English   中英

最終的多線程保證與 Java 中的 memory model 有何關系?

[英]How are the final multi-threading guarantees and the memory model related in Java?

memory model 在17.4 中定義。 Memory Model

final字段多線程保證在17.5 中給出。 最終字段語義

我不明白為什么這些是單獨的部分。

AFAIK final和 memory model 都提供了一些保證。
任何真正的程序執行都必須尊重這兩個保證。
但現在很清楚, final保證是否適用於用於驗證17.4.8 中的因果關系要求的中間執行。 執行和因果關系要求

另一個不清楚的時刻是17.5.1。 final Fields 的語義定義了一個新的“特殊” happens-before ,它不同於 memory model 中的happens-before

這種發生前排序不會與其他發生前排序傳遞關閉。

如果這些是相同的happens-before ,那么happens-before不再是偏序(因為它不是傳遞的)。
我不明白這怎么不會破壞事情。

如果這些是不同happens-before ,那么不清楚17.5 中的那個是什么。 final 字段語義可以。
17.4中的happens-before Memory Model用於限制讀取可以返回的內容:

非正式地,如果沒有發生之前的命令以防止讀取,則允許讀取r查看寫入w的結果。

但是17.5。 final 字段語義是一個不同的部分。

特殊的“最終字段保證”部分是后來的附加組件。 文檔有時會遵循歷史的怪癖——可能,如果在 JMM 的第一個版本之前發現了“最終現場保證”問題,那么文檔的結構會有所不同。

換句話說,您要問“為什么這些東西在單獨的章節中”,也許答案是:“因為它是在 java 的更高版本中添加的,因此它是在完全不同的時間編寫的;一個新的章大概是添加更多文檔的最簡單方法”。 當然,我們現在談論的是幾十年前。

§17.5 解釋了它的目的。 引用:

最終字段的使用 model 很簡單:在該對象的構造函數中為 object 設置最終字段; 並且不要在對象的構造函數完成之前在另一個線程可以看到它的地方編寫對 object 的引用。 如果遵循這一點,那么當另一個線程看到 object 時,該線程將始終看到該對象的最終字段的正確構造版本。 它還將看到任何 object 或由最終字段引用的數組的版本,這些最終字段至少與最終字段一樣最新。

換句話說,在遙遠的過去,你可以這樣做:

線程 A:

  • 制作一個新的 object。 構造函數“表現良好” 1
  • 將這個新 object 的 ref 傳遞給另一個線程。 可能以不安全的方式進行。

線程 B:

  • 接收線程獲得正確的 ref (要么是因為您通過同步安全地完成了它,即正確設置之前發生的關系,要么因為您不安全地完成了它,但 JMM 不保證不安全的代碼無法工作:它可能仍然有效)。
  • 它調用這個 object 的方法。
  • 說 object 見證了一個未初始化的final標記字段,因為初始化確實發生在線程 A 中,但不存在發生之前的關系,並且重新排序和其他惡作劇意味着線程還沒有看到它。

這非常煩人。 不可變類的部分意義在於,您可以或多或少地打印出 JMM 並將其點燃。 如果您的系統是不可變類型的合並,那么您幾乎不需要關心其中的每個棘手規則。 除了,在 §17.5 存在之前,它實際上並沒有這樣解決

作為一般原則,JMM 旨在為任何 JVM 實現提供盡可能少的“手銬”,同時使 JVM 的開發盡可能簡單。 這是一條很好的路線——例如,如果 JMM 簡單地說:“JVM 可以隨時自由地重新排序它想要的任何東西,並隨時緩存它想要的任何東西”,然后編寫 JVM根據規范快速運行代碼會“更容易”(JVM impls 會更快),但是,編寫實際執行您想要的多線程代碼變得不可能。 另一方面,JMM 還可以保證在 JVM 中重新訂購是不可能觀察到的,無論環境或架構如何。 但是 JVM 會像糖蜜一樣慢,請參閱 Python 及其備受詬病的全局解釋器鎖。

JMM 試圖成為愉快的妥協。 §17.5 也是以同樣的精神寫成的。

它基本上說:

  • 您可以相信任何行為良好的構造都意味着final字段將正常運行,而不必擔心發生之前的關系。
  • 但是,您根本不能依賴JVM 如何實現保證。 特別是,我們已經根據 Happens-Before 定義了您可以完全依賴的內容,但這與 JMM 的 rest 所談論的 HB 不同。 我們向您保證,良好的構造意味着最終字段不會成為問題,但就我們的保證而言:您不能使用此保證來強制其他保證退出 JMM; 例如,您不能將此機制用作為其他東西建立 HB 的不穩定方式。

JMM 為 JVM impls 購買了回旋余地。 JVM impl 是否實際使用它,取決於 JVM 實現者。 換句話說,JVM 實現者很可能決定通過使用它用來保證 §17.4 中的 HB 內容的相同鎖定機制來實現 §17.5,因此您可以有效地應用諸如“HB 關系是可傳遞的”之類的屬性。 JMM 的部分目的是允許 JVM impls 采取一些截然不同的方法保證它所規定的保證實際上得到保證。 這是因為必須編寫 JVM,以便它們可以在各種硬件上以與本地代碼一樣快的速度運行代碼,同時仍然是一個並非不可能開發的目標平台。

相當走鋼絲。 這是 JMM 的主要潛在解釋有時可能是遲鈍和奇怪的。

[1] 一個“行為良好”的構造函數:

  • 在構造過程中,不會將自己的引用 ( this ) 傳遞給其自己的 class 之外的任何代碼。
  • 不調用它自己的任何實例方法,然后讀取它自己的字段(或者,特別有問題,可以被子類覆蓋,其實現使用自己的字段)。 基本上:調用任何非最終方法都是即時的“你表現不好”的違規行為。
  • 不發送任何 object 引用我希望在構建期間存儲在字段中以在其他類中編碼的東西。 即使它在這樣做之前已經將其分配給最終字段。

暫無
暫無

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

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