2017-07-29 62 views
3

我是多線程新手。我想寫一個程序,我有兩個線程。一個線程打印奇數,然後放棄使用wait()和類似的其它線程打印偶數的監視器鎖定並打印
我有4個班Java代碼 - 線程彼此阻塞

  1. Odd.java號碼後放棄鎖(打印1-100之間奇數)
  2. Even.java(印刷甚至1-100之間數)
  3. SomeMaths.java(已得到邏輯用於打印奇數和偶數)
  4. OEApp.java(啓動線程的主類)

問題 - 我的代碼按預期工作,大部分時間,即按順序打印1到100。這兩個線程輪流。但我注意到,有一個bug.Sometimes偶數線程被安排第一,並得到如下輸出

2 ********** 
1 ############################### 

,沒有什麼會打印後,貌似有一個死鎖情況。我無法弄清楚爲什麼。請幫我理解這個

public class SomeMaths { 

    public synchronized void printOdd(){ 
     for(int i=1;i<=100;i++){ 
      if(i%2 !=0) { 
       System.out.println(i + "  ###############################"); 
       try { 
        wait(); 
       } catch (InterruptedException e) { 
        e.printStackTrace(); 
       } 
      } 
      notify(); 
     } 
    } 

    public synchronized void printEven(){ 
     for(int i=1;i<=100;i++){ 
      if(i%2 ==0){ 
       System.out.println(i +" **********"); 
       try { 
        wait(); 
       } catch (InterruptedException e) { 
        e.printStackTrace(); 
       } 
      } 
      notify(); 
     } 
    } 
    } 

public class Odd implements Runnable { 

    SomeMaths sm; 

    public Odd(SomeMaths sm){ 
     this.sm = sm; 
    } 
    @Override 
    public void run(){ 
     sm.printOdd(); 
    } 
} 

public class Even extends Thread { 

    SomeMaths sm; 

    public Even(SomeMaths sm){ 
     this.sm = sm; 
    } 

    @Override 
    public void run(){ 
     sm.printEven(); 
    } 
} 

public class OEApp { 

    public static void main(String[] args) { 

     SomeMaths sm = new SomeMaths(); 

     Thread odd = new Thread(new Odd(sm)); 
     Thread even = new Thread(new Even(sm)); 

     odd.start(); 
     even.start(); 

     try { 
      odd.join(); 
      even.join(); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
    } 
} 
+0

*好奇:*如果'Even'延伸'Thread',你爲什麼用'新主題(新連(SM))'另一個線程封裝器呢? – Andreas

回答

6

我相信它的工作原理是這樣的:

  1. 即使線程開始,1是奇數,因此呼叫通知(通知沒有人),則圖2是即便如此,它顯示一條消息,並等待

  2. 奇數線程開始,1是奇數,因此打印消息並等待

  3. 有沒有人打電話通知所以兩個線程永遠等待

+0

我正要問什麼是解決方案,但後來意識到問題並沒有要求解決方案,只解釋了爲什麼,所以+1從我這裏。 – Andreas

-2

什麼是您使用同步關鍵字目的是什麼?
它只能向你保證你的函數不會同時運行多次。

我假設你想讓一個線程通知另一個線程?是對的嗎 ?
但是如果在發生等待之前調用通知怎麼辦?

你知道你可以使用調試器來查看每個線程,從而知道每個線程卡在哪裏?

請記住,一旦開始被調用,你不能知道哪個線程將有CPU時間。

而且你正試圖(通過使用通知/等待mecanism的)同步兩個線程,但也有將被證明是簡單的(例如信號其他mecanisms:每個線程有它自己的信號,獲取它擁有信號量並釋放另一個信號量;初始化每個信號量爲1,它會順利進行)。

P.S. :

+1

*「您使用synchronize關鍵字的目的是什麼?」*其中之一是使用'notify()'和'wait()'時需要,所以這是一個愚蠢的問題。 – Andreas

+0

*「爲什麼要同時使用runnable和線程接口?」*因爲建議實現'Runnable'而不是擴展'Thread',這意味着您將在代碼中使用這兩個接口。請參閱[「實現Runnable」與「擴展線程」](https://stackoverflow.com/q/541487/5221149)。 – Andreas

+0

您對「爲什麼同時使用runnable和線程界面?」發表評論有點奇怪:我沒有建議使用它們中的任何一個,但詢問了使用它們的原因。 – lemmel