2015-06-23 36 views
0

我有以下問題:爲什麼在這種情況下,第二個線程時看到的第一個線程改變號碼的價值:Java併發

public static void main(String[] args) throws InterruptedException { 

    Temp t = new Temp(); 
    t.go(); 
} 

static class Temp { 
    int number = 2; 

    public void go() { 

     new Thread(new Runnable() { 

      @Override 
      public void run() { 
       try { 
        Thread.sleep(5000); 
       } catch (InterruptedException e) { 
        e.printStackTrace(); 
       } 

       number = 100; 
      } 
     }).start(); 

     new Thread(new Runnable() { 

      @Override 
      public void run() { 
       while (true) { 
        System.out.println(number); 
       } 
      } 
     }).start(); 
    } 
} 

我預計從第二個線程,當緩存的數值第一個線程改變它,第二個線程將會「不知道」,並且它將始終打印2!但實際上當第一個線程改變了數字變量時,第二個線程看到了這個改變並開始打印100.爲什麼?我知道第二個線程不會100%確定會緩存這個變量,但在大多數情況下它會這樣做。我缺少一些重要的事情。 在此先感謝。

+2

兩個線程都訪問對象級別的數字變量。沒有你想象的那樣的緩存。我會好奇爲什麼它應該與這裏不同。這種線程間通信模型被稱爲「共享內存」。 –

+0

首先你不能聲明一個類是靜態的! – Hiru

+0

如前所述,該變量是用於創建兩個線程的'Temp'實例的一部分,因此兩個線程都可以訪問該_very相同實例及其數據。 – Thomas

回答

8

根據Java內存模型它不保證由一個線程更改的值將從另一個線程可見。然而它並沒有說相反的情況:它可以被看到。這取決於虛擬機和硬件的實施。如果它現在在您的CPU上與虛擬機一起顯示,並不意味着它會在每個硬件和每臺虛擬機上始終可見。你不能依靠這個。

如果您仍然希望看到的效果,你可以替換爲下面一個第二個線程代碼:

new Thread(new Runnable() { 

    @Override 
    public void run() { 
     while (number < 100) { 
     } 
     System.out.println(number); 
    } 
}).start(); 

這將產生HotSpot虛擬機上穩定的結果:你的程序永遠不會結束(雖然加入volatilenumber字段上的關鍵字會在5秒內結束)。當然你也不能依賴這個。

+0

謝謝。你試過這個嗎?循環是無限的? – DPM

+0

請您給出相關文檔部分的鏈接。 –

0

這就是所謂的「共享內存」。

變量「number」在兩個線程(堆)共享的內存中,而不是在每個線程堆棧上。

這就是爲什麼在一個線程中改變它反映在另一個線上的原因。

+0

當我們可以擁有這個「隱身」,爲什麼?你能舉一個小例子解釋嗎? 謝謝 – DPM