2013-07-12 64 views
2

我正試圖解決一個多線程問題,我正面臨着難以瞭解其行爲。多線程 - 甚至是奇數序列

的問題是: 有2個線程,其同時消耗甚至奇數號碼。我必須介紹它們之間的線程通信,以自然排序的方式使「消耗」

這裏是我的代碼

public class EvenOddDemo { 

    public static void main(String[] args) { 
     Number n = new Number(); 
     EvenThread et = new EvenThread(n); 
     OddThread ot = new OddThread(n); 
     et.start(); 
     ot.start(); 
    } 

} 

class EvenThread extends Thread { 

    private Number number; 

    public EvenThread(Number number) { 
     this.number = number; 
    } 

    @Override 
    public void run() { 
     for(int i=0; i<5; i++) { 
      System.out.println(number.getEven()); 
     } 
    } 


} 

class OddThread extends Thread { 

    private Number number; 

    public OddThread(Number number) { 
     this.number = number; 
    } 

    @Override 
    public void run() { 
     for(int i=0; i<5; i++) { 
      System.out.println(number.getOdd()); 
     } 
    } 


} 

class Number { 

    private int currentEven = 0; 

    private int currentOdd = 1; 

    private volatile String last = "odd"; 

    public synchronized int getEven() { 
     if("even".equals(last)) { 
      try { 
       wait(); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 
     int i = currentEven; 
     last = "even"; 
     currentEven +=2; 
     notify(); 
     return i; 
    } 

    public synchronized int getOdd() { 
     if("odd".equals(last)) { 
      try { 
       wait(); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 
     int i = currentOdd; 
     last = "odd"; 
     currentOdd +=2; 
     notify(); 
     return i; 
    } 
} 

和輸出

0 
2 
1 
3 
4 
5 
7 
6 
8 
9 

但是,當我調試的代碼,它以正確的順序打印號碼。因此我無法弄清楚我錯過了什麼。請幫幫我。預先感謝您爲此主題準備的時間。

+1

有此功課SO的*衆多*的DUP。這裏是一個:http://stackoverflow.com/questions/6017281/odd-even-number-printing-using-thread?rq=1和另一個http://stackoverflow.com/questions/16689449/printing-even-and-奇數使用兩線程在Java?rq = 1 –

+0

@BrianRoach感謝您的評論。然而,我正在做'notify'和'wait'在相同的'Number'實例..所以它怎麼不適合我? – sanbhat

+2

只是爲了記錄,調試多線程應用程序並不能保證您的行爲正常,它可能會給您一次(或者可能總是)正確的結果,並且永遠不會顯示真正的問題。 –

回答

5

據我所看到的,沒有什麼阻止這種情況的發生,解釋爲什麼2在你的輸出1之前顯示:

OddThread  EvenThread 
---------- ---------- 
gets odd 
       gets even 
       prints even 
prints odd 

鎖定,因此需要將整個序列圍繞「獲取/打印」。

您會注意到,在輸出中,您永遠不會「相差兩位數」。

+1

這正是問題 - 我抓我的頭(並使用notifyAll +在循環中調用等待將是一個好主意)。 – assylias

+0

非常感謝..我在'getOdd','getEven'方法中添加了print語句,並且它非常完美! – sanbhat

2

notify選擇任何可用的線程。

的選擇是任意的,如果有兩個以上的線程在等待,你可能意味着將「錯誤」的線程發生在執行

的自由裁量權。

另外,請注意,您的兩個線程都可能在剛剛完成時得到(偶數|偶數),而且兩個都沒有等待,導致通知無法執行,具體取決於調度。

您需要更加嚴格以確保排序。也許兩把鎖,偶數和奇數都會有幫助。

+0

感謝@保爾爲你的想法 – sanbhat

0

您需要在getEven和getOdd函數中打印數字並通知其他線程。 但你通知並打印數量,所以的NotI 修改後的代碼之間:

public class ThreadExp { 

    public static void main(String[] args) { 
     Number n = new Number(); 
     EvenThread et = new EvenThread(n); 
     OddThread ot = new OddThread(n); 
     et.start(); 
     ot.start(); 
    } 

} 

class EvenThread extends Thread { 

    private Number number; 

    public EvenThread(Number number) { 
     this.number = number; 
    } 

    @Override 
    public void run() { 
     for (int i = 0; i < 10; i++) { 
      number.getEven(); 
     } 
    } 

} 

class OddThread extends Thread { 

    private Number number; 

    public OddThread(Number number) { 
     this.number = number; 
    } 

    @Override 
    public void run() { 
     for (int i = 0; i < 10; i++) { 
      number.getOdd(); 
     } 
    } 

} 

class Number { 

    private int currentEven = 0; 

    private int currentOdd = 1; 

    private StringBuilder odd; 
    private StringBuilder even; 
    private StringBuilder last; 

    { 
     odd = new StringBuilder("odd"); 
     even = new StringBuilder("even"); 
     last = odd; 
    } 

    public synchronized void getEven() { 
     if (last == even) { 
      try { 
       //System.out.println("inside if in even--->" +Thread.currentThread()); 
       wait(); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 
     //System.out.println("out of if in even--> " + Thread.currentThread()); 
     int i = currentEven; 
     last = even; 
     currentEven += 2; 
     System.out.println(i); 
     notify(); 
     return; 
    } 

    public synchronized void getOdd() { 
     if (last == odd) { 
      try { 
       //System.out.println("inside if in odd--->" +Thread.currentThread()); 
       wait(); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 
     //System.out.println("out of if in odd--> " + Thread.currentThread()); 

     int i = currentOdd; 
     last = odd; 
     currentOdd += 2; 
     System.out.println(i); 
     notify(); 
     return; 
    } 
}