2012-07-30 55 views
2

我只是想寫一個例子的競爭條件:一個簡單的Java競爭條件

MyParallelClass.java

public class MyParallelClass implements java.lang.Runnable { 
    public int counter = 0; 

    @Override 
    public void run() { 
     if (test.globalVar > 0) { 
      for (int i = 0; i < 1000000; i++) { 
       counter++; 
      } 
      test.globalVar--; 
     } 
    } 
} 

test.java

public class test { 
    public static int globalVar; 

    public static void main(String[] args) { 
     globalVar = 1; 

     MyParallelClass a = new MyParallelClass(); 
     MyParallelClass b = new MyParallelClass(); 

     new Thread(a).start(); // Thread A 
     new Thread(b).start(); // Thread B 

     System.out.println(globalVar); 
    } 
} 

我以爲會發生:

如果線程A在線程B啓動之前完全執行,我認爲這可以輸出0

變量test.globalVar也能拿操作是這樣的:

Thread A      - Thread B 
checks if (globalVar > 0) 
     looping ...    checks if (globalVar > 0) 
     looping ...    execute all four bytecode commands of "test.globalVar--;" 
     execute test.globalVar--; 

所以test.globalVar的價值將是-1

因此,任何一個if語句都會被執行或者兩者都執行。

實際發生的事情:

01爲主要手段的輸出。爲什麼我得到01而不是0-1

+0

線程執行的順序不能保證。這是在操作系統上的憐憫。 – kosa 2012-07-30 19:35:01

+1

我的0和1是什麼意思?你是否試圖在main的System.out.println(globalVar)之外的地方打印globalVar? – 2012-07-30 19:35:37

+3

嘗試在打印globalVar之前連接兩個線程。在兩個線程都有機會完成之前,您可能已經到達主要方法的最後一行。如果1結束,則以0結束,如果兩次都沒有完成,那麼您得到1。 – 2012-07-30 19:36:34

回答

1

System.out.println(globalVar); 

不等待線程完成。線程可能會或可能不完整。因此,值可以是0,1-1,具體取決於線程是否完成,一個完成還是兩個都未完成。

爲了有一個更好的測試,
- 使用線程Thread.sleep(),以確保有一個延遲
- 在不同的線程使用不同的延遲,以更好地可視化競爭狀態。
- 您可能還想在線程中打印該變量的值。這樣你有三個線程在比賽(A,B和主線程),你可以獲得更好的可視化。

0

好問題。我認爲你需要運行更多的測試。 :-)

您可能會嘗試更改Runnable類中的循環以隨機數毫秒(500-1000)進行睡眠。循環10次。看看你是否沒有得到你預期的競爭條件。

我認爲大多數電腦太快了。你很簡單的循環可能沒有做足夠的工作來引起線程切換。

我喜歡這類問題,因爲我一直遇到像這樣的錯誤。

3

您正在遞減globalVar兩次。的globalVar末可能的值是:

  • -1 - 如果一切都很好,兩個線程都正確地減少它付印前值

  • 0

    • 如果只一個線程設法減小變量,第二個線程在打印之前未完成設置

    • 如果globalVar在同一時間

  • 1遞減:

    • 如果System.out.println()設法執行兩個線程完成之前(完全有可能)。該globalVar確實進行了修改,但之後它已經印刷

    • 由於能見度問題main線程看到原來globalVar值,而不是一個由不同的線程修改。您需要某種同步或volatile關鍵字才能立即(或曾經)看到其他線程所做的更改。

0

如果在任何線程遞減該值之前打印該值,則可以得到1。