2012-11-18 25 views
4

讓我們下面的語句:獨立指令可以通過Java編譯器或JVM交換指令順序嗎?

int d0, d1; 
int[] ds = {0, 0}; 

現在一個線程具有以下說明:

d0++; 
d1++; 

而另一個線程指令:

ds[1] = d1; 
ds[0] = d0; 

如果我們並行運行這些線程,顯然有三種組合可以看作:{0,0},{1,1}和{1,0}。

現在最大的問題是:還可以有{0,1}嗎?編譯器/ JVM可以簡單地交換指令,因爲它認爲它們不相關?如果是,那麼這些行爲的「規則」究竟是什麼,是由編譯器還是JVM決定?

+1

通常優化被認爲是安全的,如果它們的行爲與串行(iow,一個線程)模型中未優化的代碼相同。除非相關的語言結構對線程有明確的規定 –

回答

6

是的,{0, 1}也是可能的。 Java內存模型不足以保證在這種情況下的排序。這甚至不需要指令重新排序 - 如果您在x86或x86_64以外的任何地方運行該程序,無論如何都會發生這種情況。

在這裏要清楚,實際的CPU硬件將重新排序這些加載和存儲,而不是如果它是x86。

Java Memory Model FAQ

0

是兩者的編譯器和JVM(剛剛實時編譯器)可以做的指令重新排序。而且,硬件處理器可以做到。爲了防止不必要的重新排序,應該使用memory barriers

2

如果沒有正確的同步,這確實是可能的。

Java語言規範在第17章中定義了多線程Java程序的語義。這一章很難理解,但它確實包含了可以依賴的官方規則。特別是,writes

存儲器模型描述給定該程序的程序和執行軌跡,確定執行軌跡是否是程序的合法執行。 Java編程語言內存模型通過檢查執行跟蹤中的每個讀取並根據特定規則檢查該讀取觀察到的寫入是否有效來工作。

存儲器模型描述程序的可能行爲。一個實現可以自由產生任何它喜歡的代碼,只要一個程序的所有執行結果產生一個可以被內存模型預測的結果。

爲了給出一個粗略的概貌,內存模型定義了happens-before relation任何重新排序必須consistent with。通常的建立方式在不同線程執行動作之前發生,例如synchronize這些動作,例如使用​​塊或寫入或讀取易失性變量。

在沒有這種同步的情況下,運行時將獨立執行線程,允許任何重新排序的線程無法觀察到的當前線程。

也就是說,如果你有可變的共享狀態,你通常需要同步訪問它的線程。