2015-05-09 78 views
2

我試圖做到這一點:創建兩個不同的線程,一個打印奇數,一個打印偶數。一旦一個線程打印一個數字,它就必須等待另一個線程等等,這是一個接一個的。程序獲取暫停:wait()和notify()

爲了實現這一點,我使用同步塊與wait()和notify()。

我正在創建一個類,其對象將用於傳遞到兩個線程中的同步塊。

下面是代碼:

- >這是用來將被傳遞給同步塊的對象。

package com.vipin.multithread.variousdemos; 

    public class SyncObject { 

     public SyncObject() { 

     } 
} 

奇主題:

package com.vipin.multithread.variousdemos; 

public class OddThread implements Runnable { 

private Thread t; 
int index=0; 
SyncObject so=null; 

int odd_nums[] = {1,3,5,7,9}; 

public OddThread(SyncObject so) { 
    t = new Thread(this,"Odd Thread"); 
    this.so = so; 
    t.start(); 
} 

public Thread getThreadInstance() { 
    return t; 
} 

@Override 
public void run() { 
    while (true) { 
     synchronized(so) { 
      System.out.println("Odd num is --->" + odd_nums[index]); 
      try { 
       so.wait(); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
      index++; 
      so.notify(); 
      if(index>=5) { 
       return; 
      } 
     } 
    } 
} 
} 

即使主題:UPDATE

package com.vipin.multithread.variousdemos; 

public class EvenThread implements Runnable { 

private Thread t; 
int index=0; 
SyncObject so=null; 

int even_nums[] = {2,4,6,8,10}; 

public EvenThread(SyncObject so) { 
    t = new Thread(this, "Even thread"); 
    this.so = so; 
    t.start(); 
} 

public Thread getThreadInstance() { 
    return t; 
} 

@Override 
public void run() { 
    while(true) { 
     synchronized(so) { 
      System.out.println("Even num is --->" + even_nums[index]); 
      so.notify(); <-- Here we are notifying. 
      try { 
       so.wait(); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
      index++; 
      //so.notify(); <-- commented out. 
      if(index>=5) { 
       break; 
      } 
     } 
    } 
} 
} 

主要用途:

package com.vipin.multithread.variousdemos; 

public class EvenOddDemo { 

public static void main(String[] args) throws InterruptedException { 
    SyncObject so = new SyncObject(); 

    OddThread ot = new OddThread(so); 
    EvenThread et = new EvenThread(so); 

    System.out.println("\nIn main thread"); 

    Thread.sleep(1000000000); 

    System.out.println("Exiting main thread..."); 
} 
} 

--->正如代碼所示,我創建兩個線程來打印偶數和奇數。我正在使用同步塊,並傳遞類型==> SyncObject的對象。

SyncObject我作爲參數傳遞給main中的這些不同的線程。

然而,這種程序停止,即堅持只有得到執行的第一條語句,然後將它永遠等待:

這裏是輸出:

奇num是---> 1

在主線程 偶數是---> 2

我不明白爲什麼這個程序等待永遠,我正在使用我們調用synchronized(),wait()和notify()的SAME對象。根據我的理解,它應該工作,不知道爲什麼這不起作用。

任何線索,爲什麼這是永遠等待。

更新:

我在代碼中做了一些更改,UPDATE並且工作正常。

我還有一些疑問。 notify()是否被線程調用,即使它沒有鎖定監視器,就像在我更新代碼之後的情況一樣。

事件序列:

奇線程最先被執行,然後調用wait()的< - 它釋放的顯示器,現在處於睡眠模式。

即使線程運行,打印消息,並調用通知()< - 在這裏我沒有清楚的理解。

當即使線程調用notify(),在那一點上它有監視器,所以當它調用notify()時,它是否仍然擁有監視器?

現在,即使線程調用notify()之後,Odd線程也會得到通知,因此它會從它正在休眠的位置開始執行。它正在執行一些執行並調用notify(),在那一點上,我認爲Odd線程不擁有監視器,它調用notify()。所以,我的問題是,不管線程是否擁有顯示器,notify()是否工作相同?

只有當一個人做的代碼,一個真正理解這一點。我讀書,我覺得我明白了一切,似乎我已經回到了原點!

+0

1)直到檢查到有需要等待的東西時才調用wait。 2)在某個地方,你必須存儲你正在等待的東西,即哪個線程應該下一個去。沒有它,線程就沒有辦法知道它是否應該等待,或者是否應該時間工作。 –

回答

2

這裏的問題很簡單,就是兩條線都直接等待。線程1得到so,打印值然後等待。線程2然後得到so,打印值然後等待。所以兩人都在睡覺,因爲沒有人通知他們。所以,一個簡單的修復就是so.notify(),就在so.wait()之前。然後,他們並沒有無限期待。

編輯

奇線程開始,執行&然後等待。然後,即使線程啓動,執行,然後通知&等待。即使線程在顯示器上保持鎖定,直到它進入等待狀態。

當偶數線程調用通知時,奇數線程喚醒鎖定的輪詢&。一旦偶線程進入等待狀態(&釋放鎖定),則奇線程可以獲得鎖定。

如果偶數線程沒有調用通知,那麼奇數線程將繼續睡眠。偶線會去&發佈鎖定。沒有線程正在輪詢或嘗試獲取鎖,因此程序保持暫停狀態。

documentation也提供了類似的解釋。我希望這清除你的疑惑。

+1

+1。並且不要忘記在'OddThread'中添加'if(index> = 5){so.notify(); return;}'來喚醒'EvenThread'。 –

+0

根據文檔,wait()解鎖監視器,然後停止執行調用它的線程。這是基於我編碼。考慮到,首先執行OddThread,然後調用wait(),此時它將解鎖監視器並暫停執行,然後EvenThread將執行,並在遇到wait()時解鎖監視器並暫停執行。所以,在什麼地方我們必須調用notify()。有了這個模型,我們就沒有機會通知()了。我看過代碼wait().. notify();和其他線程也wait()..通知()..我不知道我在這裏失蹤! – CuriousMind

+0

是的,wait()表示解鎖監視器並暫停執行。但是,這並不意味着其他線程開始執行。他們也處於「停止」模式。 Notify()告訴他們現在重新開始執行。 通常,在wait()語句優先,然後是notify()的地方編寫程序,但是在執行時,您會發現一個線程正在等待(),而另一個線程跳過並繼續通知()。 Wait()語句通常在某種情況下。 – Vineet