大免責聲明
一些我在這裏寫的事情實際上測試 - 就像重新排序,沖洗等;他們中的一些人花了很多時間閱讀,我希望我說得對。
一切被重新排序,而不是重新排序的策略,讓你的程序運行它在數年前下降了道路。只要輸出不改變,操作就會按照他們的要求重新排序。
例如:
static int sum(int x, int y){
x = x + 1;
y = y + 1;
return x + y;
}
你真的不關心爲了在實現這些工作,只要結果是正確的,你做了什麼?
沒有內存屏障(通常稱爲StoreLoad|StoreStore|LoadStore|LoadLoad
),任何操作都可能發生變化。爲了保證有些操作不需要move beyond a fence
,有cpu fences
執行。 Java有幾種生成方法 - volatile
,synchroniztion
,Unsafe/VarHandle
(可能有其他的,我不知道)。
基本上當你寫一個volatile例如,出現這種情況:
volatile x...
[StoreStore] - inserted by the compiler
[LoadStore]
x = 1; // volatile store
[StoreLoad]
...
[StoreLoad]
int t = x; // volatile load
[LoadLoad]
[LoadStore]
讓我們這個例子的一個子集:
這意味着任何Store
或的Load
變量不能用x = 1
重新排序。同樣的原則適用於其他障礙。
馬丁湯姆森說,那是什麼on x86
4分之3的屏障是免費的,已被髮出的只有一個:StoreLoad
。它們是免費的,因爲x86具有強大的內存模型,這意味着其他操作默認情況下不會重新排序。在其他的CPU上,其中一些操作也相當便宜(如果我在ARM
上有錯誤lwsync
- 輕量級同步;名稱應該是自解釋的)。
此外,CPU和緩存之間還有一點緩衝區 - 稱爲Store Buffer
。當您將某些內容寫入變量時,它不會直接進入緩存(s)。它進入該緩衝區。當它已滿(或被強制通過StoreLoad
排空)時,它會將寫入寫入緩存 - 並且最多可以使用cache coherency protocol
來同步所有緩存中的數據。
馬丁說,如果你有多個作家,你必須多次發出StoreLoad
- 因此它是昂貴的。如果你有一個作家,你不需要。緩衝區滿時會排空。什麼時候發生?那麼有時,理論上可能永遠不會,實際上相當快。
一些很棒的資源(這些資源有時讓我整夜都沒有睡覺,所以小心!):
這些一StoreStore
順便說一句你寫的每一個最終的變量在構造函數中時間:
private final int i ;
public MyObj(int i){
this.i = i;
// StoreStore here
}
LazySet
Shipilev Volatile
And my all time favorite!
您使用的是Java。您應該尊重Java內存模型。不是x86/64內存模型。 –