2013-03-25 35 views
4

我一直在閱讀Java內存模型,並且我知道編譯器可以重新組織語句以優化代碼。測量時間間隔和亂序執行

假設我有以下代碼:

long tick = System.nanoTime(); 
function_or_block_whose_time_i_intend_to_measure(); 
long tock = System.nanoTime(); 

將編譯器重新組織過的代碼的方式,我打算來衡量是不是蜱和滴答之間執行?例如,

long tick = System.nanoTime(); 
long tock = System.nanoTime(); 
function_or_block_whose_time_i_intend_to_measure(); 

如果是這樣,那麼保留執行順序的正確方法是什麼?

編輯: 實施例示出了亂序執行與nanoTime:上述代碼

public class Foo { 
    public static void main(String[] args) { 
     while (true) { 
      long x = 0; 

      long tick = System.nanoTime(); 
      for (int i = 0; i < 10000; i++) { // This for block takes ~15sec on my machine 
       for (int j = 0; j < 600000; j++) { 
        x = x + x * x; 
       } 
      } 

      long tock = System.nanoTime(); 
      System.out.println("time=" + (tock - tick)); 
      x = 0; 
     } 
    } 
} 

輸出:

time=3185600 
time=16176066510 
time=16072426522 
time=16297989268 
time=16063363358 
time=16101897865 
time=16133391254 
time=16170513289 
time=16249963612 
time=16263027561 
time=16239506975 

在上述例子中,在第一次迭代中所測量的時間是顯著低於後續運行中的測量時間。我認爲這是由於無序執行。第一次迭代我做了什麼錯誤?

+2

我的直覺是,Java不會重新安排非內聯函數調用,因爲它無法在一般意義上知道它們可能具有哪些副作用(特別是如果函數位於不同的編譯單元中)。但我不能支持任何事情。 – Patashu 2013-03-25 03:45:13

+0

這可能是一個系統調用,它超出了Java內存模型的範圍。 – ZhongYu 2013-03-25 04:25:52

回答

0

編譯器是否會以我想要測量的內容不會在tick和tock之間執行的方式重組代碼?

都能跟得上。那從來沒有發生。如果編譯器優化混亂了,這將是一個非常嚴重的錯誤。引用wiki的聲明。

只要保證隔離線程的結果,運行時(在本例中通常指的是動態編譯器,處理器和內存子系統)可以自由引入任何有用的執行優化。與在程序中發生的聲明(也稱爲程序順序)中執行的所有聲明完全相同。

因此,只要結果與按程序順序執行時相同,就可以進行優化。在你引用的情況下,我會假設優化是本地的,並且沒有其他線程會對這些數據感興趣。這些優化是爲了減少可能成本高昂的對主內存的訪問次數。當涉及多個線程時,您只會遇到這些優化問題,並且需要知道彼此的狀態。

現在如果2個線程需要一致地看到彼此的狀態,他們可以使用易失性變量或內存屏障(同步)來強制將寫入/讀取序列化到主內存。您可能會感興趣的Infoq ran a nice article on this

0

Java存儲器模型(JMM)定義了一個名爲happens-before的部分排序,用於程序的所有操作。定義了七條規則以確保訂購happens-before。其中之一稱爲Program order rule

程序訂單規則。線程中的每個動作都會在該線程中的每個動作之前發生,該動作稍後將按程序順序進行。

根據這條規則,你的代碼不會被編譯器重新排序。

Java Concurrency in Practice給出了一個關於這個話題的很好的解釋。

+0

我還是不明白。假設我有以下代碼: 'long x,y; x = 10; // S2 y = 20; // S3 x = x + x; // S4' 編譯器優化代碼以使S2和S4依次發生,然後執行S3會不會更好。這也是安全的,因爲S3不依賴於S2或S4。通過這樣做,可以完成S4的計算,而x仍然在S2的寄存器中。我認爲這是亂序執行的重點。 現在假設我用'y = System.nanoTime();'替換了S3。是否有一個「發生之前」的規則解釋了這一點? – 2013-03-26 05:52:37