2013-10-23 61 views
1

有人可以解釋這段代碼中競爭條件的位置嗎?我的講師設定了它,但我不完全理解如何發現它們,或者說出發生的結果的原因。查找競爭條件

public class SlowRace { 

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

      MyThread.count = 0 ; 

      MyThread thread1 = new MyThread() ; 
      thread1.name = "A" ; 

      MyThread thread2 = new MyThread() ; 
      thread2.name = "B" ; 

      thread1.start() ; 
      thread2.start() ; 

      thread2.join() ; 
      thread1.join() ; 

      System.out.println("MyThread.count = " + MyThread.count) ; 
     } 
    } 

    class MyThread extends Thread { 

     volatile static int count ; 

     String name ; 

     public void run() { 

      for(int i = 0 ; i < 10 ; i++) { 
       delay() ; 
       int x = count ; 
       System.out.println("Thread " + name + " read " + x) ; 
       delay() ; 
       count = x + 1; 
       System.out.println("Thread " + name + " wrote " + (x + 1)) ; 
      } 
     } 

     static void delay() { 

      int delay = (int) (1000000000 * Math.random()) ; 
      for(int i = 0 ; i < delay ; i++) {} 
     } 
    } 

被返回的結果是:

Thread A read 0 
Thread A wrote 1 
Thread B read 0 
Thread A read 1 
Thread B wrote 1 
Thread A wrote 2 
Thread B read 2 
Thread A read 2 
Thread B wrote 3 
Thread A wrote 3 
Thread B read 3 
Thread A read 3 
Thread B wrote 4 
Thread A wrote 4 
Thread B read 4 
Thread A read 4 
Thread B wrote 5 
Thread A wrote 5 
Thread B read 5 
Thread A read 5 
Thread B wrote 6 
Thread A wrote 6 
Thread B read 6 
Thread A read 6 
Thread B wrote 7 
Thread A wrote 7 
Thread B read 7 
Thread A read 7 
Thread B wrote 8 
Thread A wrote 8 
Thread B read 8 
Thread A read 8 
Thread B wrote 9 
Thread A wrote 9 
Thread B read 9 
Thread A read 9 
Thread B wrote 10 
Thread A wrote 10 
Thread B read 10 
Thread B wrote 11 
MyThread.count = 11 
+0

'count'它XDDD – RamonBoza

+0

你能擴大嗎? – rob1994

+0

「靜態詮釋計數」不再多說了:) –

回答

2

嗨可能有人解釋其中的競爭條件是在這一段代碼,

比賽是這些線之間:

  int x = count ; 
      ... 
      count = x + 1; 

一個線程獲取值,但另一個線程可能在之前獲得相同的值第一個線程使用遞增的值更新值。這就是比賽。

  1. thread-1得到值count並將其存儲在x中。 (假設10)。
  2. 與此同時,線程2也獲得值count並將其存儲在x中。 (假設10)。
  3. 線程1遞增x11並將其存回count
  4. 線程2將其副本x遞增爲11並將其存回count - 這會覆蓋線程1的增量。

所以不是count爲12,增量的人會被丟失,這將是11

演習是指出,增量不是原子。真的delay()是沒有必要的。 count++也可以證明這個問題,因爲它不是原子的(get/increment/set),並且線程可以在3次操作中被中斷。

使代碼複雜化的一件事是System.out.println(...)是同步的,所以控制檯輸出將改變程序的時間。

+1

他們解釋在Java這一權利雪道:http://docs.oracle.com/javase/ tutorial/essential/concurrency/interfer.html – Cruncher

+0

那麼你將如何通過使用鎖定變量來解決這個問題? – rob1994

+1

@ rob1994如果你有一個專用於鎖的最終對象,只需在讀和寫周圍放置'synchronized(lock){// code}'。 – Cruncher

0

您正在告訴編譯器將信息存儲在內存而不是緩存中。

volatile static int count ; 

2個線程在同一時間執行此運行。

public void run() { 

     for(int i = 0 ; i < 10 ; i++) { 
      delay() ; 
      int x = count ; 
      System.out.println("Thread " + name + " read " + x) ; 
      delay() ; 
      count = x + 1; 
      System.out.println("Thread " + name + " wrote " + (x + 1)) ; 
     } 
    } 

想象一下。

count = 0; 
Thread1(int x = count); //x = 0; 
Thread1(delay) 
Thread2(int x = count); //x = 0; 
Thread2(delay) 
Thread1(count = x + 1); //count = 1; 
Thread2(count = x + 1); //count = 1; //While it has to be 2. 
0

這種邏輯是線程不安全的,因爲未保護的更新到在類MyThread的靜態變量計數的。
主線程在啓動它們之後會連接Thread1和Thread2,並等待其完成。然而,同時運行線程(Thread1,Thread2)和不正確的時序可能會導致更新變量「count」和相同的值。

+1

沒有比賽進入for塊。閱讀和寫作價值觀之間存在競爭。 – Cruncher

+0

@Cruncher:你說得對!修改了評論。 –