[英]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:
線程 B:
final
標記字段,因為初始化確實發生在線程 A 中,但不存在發生之前的關系,並且重新排序和其他惡作劇意味着該線程還沒有看到它。這非常煩人。 不可變類的部分意義在於,您可以或多或少地打印出 JMM 並將其點燃。 如果您的系統是不可變類型的合並,那么您幾乎不需要關心其中的每個棘手規則。 除了,在 §17.5 存在之前,它實際上並沒有這樣解決
作為一般原則,JMM 旨在為任何 JVM 實現提供盡可能少的“手銬”,同時使 JVM 的開發盡可能簡單。 這是一條很好的路線——例如,如果 JMM 簡單地說:“JVM 可以隨時自由地重新排序它想要的任何東西,並隨時緩存它想要的任何東西”,然后編寫 JVM根據規范快速運行代碼會“更容易”(JVM impls 會更快),但是,編寫實際執行您想要的多線程代碼變得不可能。 另一方面,JMM 還可以保證在 JVM 中重新訂購是不可能觀察到的,無論環境或架構如何。 但是 JVM 會像糖蜜一樣慢,請參閱 Python 及其備受詬病的全局解釋器鎖。
JMM 試圖成為愉快的妥協。 §17.5 也是以同樣的精神寫成的。
它基本上說:
final
字段將正常運行,而不必擔心發生之前的關系。JMM 為 JVM impls 購買了回旋余地。 JVM impl 是否實際使用它,取決於 JVM 實現者。 換句話說,JVM 實現者很可能決定通過使用它用來保證 §17.4 中的 HB 內容的相同鎖定機制來實現 §17.5,因此您可以有效地應用諸如“HB 關系是可傳遞的”之類的屬性。 JMM 的部分目的是允許 JVM impls 采取一些截然不同的方法來保證它所規定的保證實際上得到保證。 這是因為必須編寫 JVM,以便它們可以在各種硬件上以與本地代碼一樣快的速度運行代碼,同時仍然是一個並非不可能開發的目標平台。
相當走鋼絲。 這是 JMM 的主要潛在解釋有時可能是遲鈍和奇怪的。
[1] 一個“行為良好”的構造函數:
this
) 傳遞給其自己的 class 之外的任何代碼。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.