2011-09-27 29 views
1

我有一個最喜歡的C#程序類似於下面的那個,表明如果兩個線程共享相同的內存地址進行計數(一次線程遞增n次,一次線程遞減n次),您可以獲得非零的最終結果。只要n相當大,就很容易讓C#在[-n,n]之間顯示一個非零值。但是,即使將線程數增加到1000個(500個,500個),我也無法讓Java產生非零結果。有沒有一些內存模型或規格差異與C#我不知道,保證這個程序將始終屈服0儘管我沒有意識到的核心的調度或數量?我們是否同意,即使我們無法通過實驗證明,該計劃也能產生非零價值?這個Java程序可以打印非零值嗎?

(不:,我發現這個問題詢問過here,但是當我運行該主題的代碼我也得到零。)

public class Counter 
{ 
    private int _counter = 0; 

    Counter() throws Exception 
    { 
    final int limit = Integer.MAX_VALUE; 

    Thread add = new Thread() 
    { 
     public void run() 
     { 
     for(int i = 0; i<limit; i++) 
     { 
      _counter++; 
     } 
     } 
    }; 

    Thread sub = new Thread() 
    { 
     public void run() 
     { 
     for(int i = 0; i<limit; i++) 
     { 
     _counter--; 
     } 
     } 
    }; 

    add.run(); 
    sub.run(); 
    add.join(); 
    sub.join(); 

    System.out.println(_counter); 
    } 

    public static void main(String[] args) throws Exception 
    { 
    new Counter(); 
    } 
} 
+3

我猜你的意思是調用''開始的(),而不是'的run()',否則,你有沒有額外的線程在所有。 – Progman

+0

有時候我真的不明白當我的一個程序運行時Java VM內部發生了什麼。 JRE執行多次優化,在這種情況下,可以通過最終的「合併」操作對每個線程中分配給整數的值進行緩存(如變量「產卵」爲多個副本),或者是誰知道......也許線程不是「本地」的線程。我們應該看看你的平臺的JRE代碼:) – gd1

+0

哦,親愛的,只是共同的開始<>運行混亂? – gd1

回答

4

你給只運行在單個線程的代碼,所以總是會給結果0如果你真的開始兩個線程,你的確可以得到一個非零結果:

// Don't call run(), which is a synchronous call, which doesn't start any threads 
// Call start(), which starts a new thread and calls run() *in that thread*. 
add.start(); 
sub.start(); 

在我的測試運行,給了-2146200243框。

+0

毆打我一分鐘:\詛咒你Jon Skeet! –

+0

@Jon Ug。我完全打算打電話給開始。感謝您的理智檢查。 – Dejas

0

你的程序存在的問題是你沒有創建一個操作系統線程,所以你的程序本質上是單線程的。在Java中,您必須調用Thread.start()來創建新的操作系統線程,而不是Thread.run()。這與初始Java API中出現的令人遺憾的錯誤有關。那個錯誤是設計師製造Thread執行Runnable

add.start(); 
sub.start(); 
add.join(); 
sub.join(); 
2

假設你的真正用意start,不run

在大多數常見平臺上,它很可能會產生非零值,因爲在多核心情況下,++/--不是原子操作。在單核/單CPU上,如果編譯爲一條指令(add/inc),但該部分依賴於JVM,則最有可能得到0,因爲++/--是原子。

入住這裏的結果:http://ideone.com/IzTT2