2 回答

TA貢獻1848條經驗 獲得超6個贊
從技術上講,Java 語言不存在內存障礙。相反,Java 內存模型是根據發生在關系之前指定的;詳細信息請參見以下內容:
Java 中內存屏障的行為
正如該文檔所說,它是為編寫實現 Java 內存模型的編譯器的人們提供的指南。它正在解釋JMM 的含義,顯然無意成為官方規范。JLS 是規范。
JSR-133 Cookbook 中有關內存屏障的部分根據它們限制特定加載和存儲序列的方式對它們進行分類。對于StoreStore
障礙,它說:
該順序:
Store1; StoreStore; Store2
?確保 Store1 的數據在與 Store2 關聯的數據和所有后續存儲指令之前對其他處理器可見(即刷新到內存)。一般來說,StoreStore
處理器上需要屏障,否則不能保證從寫入緩沖區和/或高速緩存到其他處理器或主存儲器的刷新的嚴格順序。
正如您所看到的,StoreStore
障礙僅限制操作的行為store
。
在您的示例中,您有一個load
后跟一個store
。屏障的語義StoreStore
沒有提及load
操作。因此,您建議的重新排序是允許的。

TA貢獻1824條經驗 獲得超8個贊
這只是回答您問題的更新部分。
首先,您提供的示例不是 Java 代碼。因此我們不能對其應用 JMM 推理。(只是為了讓我們清楚這一點。)
如果您想了解 Java 代碼的行為方式,請忘記內存屏障。Java 內存模型告訴您為了使內存讀取和寫入具有有保證的行為而需要執行的所有操作。以及推理(正確)行為所需了解的一切。所以:
編寫您的 Java 代碼
分析代碼以確保在線程需要讀取另一個線程寫入的值的所有情況下,鏈之前都有正確的發生。
將(正確的)Java 代碼編譯為機器指令的問題留給編譯器。
查看示例中的偽指令序列,它們沒有多大意義。我不認為真正的 Java 編譯器在編譯真正的 Java 代碼時會(在內部)使用這樣的屏障。相反,我認為在每次易失性寫入之后和每次易失性讀取之前都會存在StoreLoad
內存屏障。
讓我們考慮一些真實的 Java 代碼片段:
public int a;
public volatile int b;
// thread "one"
{
a = 1;
b = 2;
}
// thread "two"
{
if (b == 2) {
print(a);
}
}
現在假設線程“二”中的代碼在線程“一”之后執行,將會有一個發生之前鏈,如下所示:
a = 1
發生在之前b = 2
b = 2
發生在之前b == 2
b == 2
發生在之前print(a)
除非涉及其他代碼,否則發生之前鏈意味著線程“二”將打印“1”。
筆記:
編譯代碼時無需考慮編譯器使用的內存屏障。
這些障礙是特定于實現的并且是編譯器內部的。
如果您查看本機代碼,您將不會看到內存屏障本身。您將看到具有所需語義的本機指令,以確保(隱藏的)內存屏障存在。
添加回答
舉報