2011-06-17 49 views
0

我是編程新手,所以我決定寫一個簡單的多線程程序。它顯示了餐廳的工作。客戶點菜,服務員服務和廚師準備。但是我遇到了一個問題,我認爲這是死鎖的情況,因爲當我運行它時,它會打印「排序」而沒有其他內容。我不明白什麼是錯的。請幫忙。謝謝。Java中的多線程

Restaurant.java

public class Restaurant implements Runnable{ 
Client cl=new Client(); 
Chef ch=new Chef(); 
Waiter w=new Waiter(); 

public synchronized void makeOrder() throws InterruptedException{ 
notifyAll(); 
cl.makeOrder(); 
wait(); 

} 

public synchronized void makeServing() throws InterruptedException{ 

notifyAll(); 
wait(); 

} 

public synchronized void makeFood() throws InterruptedException{ 
notifyAll(); 
ch.makeFood(); 
Thread.sleep(1000); 
wait(); 
} 

@Override 
public void run() { 
    try { 
    for(int i=0;i<10;i++){ 
     makeOrder(); 
     makeServing(); 
     makeFood(); 
    } 
    } catch (InterruptedException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 

} 

} 

Client.java

public class Client{ 
public void makeOrder(){ 
System.out.println("Ordering"+Thread.currentThread().getId()); 
} 

Waiter.java

public class Waiter { 

public void makeServe() { 
    System.out.println("Serving order"+Thread.currentThread().getId()); 

} 

Chef.java

public class Chef { 

public void makeFood(){ 

    System.out.println("Making food "+Thread.currentThread().getId()); 

} 

Main.java

public class Main { 
public static void main(String[] args) { 

    Restaurant r=new Restaurant(); 
    Thread t=new Thread(r); 
    t.start(); 
} 

}

+3

_But我有一個問題,我認爲這是deadlocking_的情況;您將不得不提供您正面臨的_problem_的詳細信息 – Nivas 2011-06-17 08:40:07

+0

另外,請提供線程正在實例化的代碼。 – Jivings 2011-06-17 08:42:10

+0

你的主要方法是什麼樣的?您發佈的代碼看起來很奇怪,但我無法看到那裏出現死鎖的原因。 – Kaj 2011-06-17 08:43:04

回答

5

當你在餐廳叫makeOrder();線程它將等待()。然後什麼都不會發生。問題是,你只有一個線程,這個不能通知自己。我認爲你想要做的是把你的客戶,服務員和廚師變成線索。然後開始他們一個接一個,然後服務員必須等待,直到客戶發出他的訂單,廚師必須等待,直到服務員拿到訂單...

你可能會發現一些有用的例子,如果你谷歌的「java生產者消費者示例「。

+0

我明白你的想法。但是現在監視器是Restaurant類的對象,如果我執行Client,Waiter和Chef線程,每個線程都會有run()方法,其中我將使用notify和wait方法調用synchronized方法。但是,什麼對象將被監控?我不能通知客戶服務員,因爲這是不同的類,所以同步發生在不同的監視器上。對嗎?這種情況下的解決方案是什麼? – andre123 2011-06-17 09:00:52

+0

您必須爲您的客戶,服務員和廚師提供參考餐廳,餐廳可能有像'orderReady'和'orderTaken'這樣的變量。它們也可能是Order對象的列表,然後客戶端將調用餐廳的makeOrder(),服務器的makeServing()等。因此,您在餐廳中仍然有一個共同的顯示器。 – morja 2011-06-17 09:19:37

0

你的代碼的工作,如果您使用的是這樣的一個主要方法(使輸出):

public static void main(String[] args) { 
    Restaurant r = new Restaurant(); 
    new Thread(r).start(); 
    new Thread(r).start(); 
    new Thread(r).start(); 
} 

程序會運行一段時間,然後將停止,因爲它會等待更多的「請求「,它並沒有陷入僵局。死鎖需要兩個不同的鎖,並且只有一個在你的代碼中。

注意,你可能仍然有合理的「瑕疵/錯誤」

1

您濫用等待/通知機制。 :-)這是真正的問題。

在Java中,wait/notify用於實現條件變量,它允許線程等待「條件」被滿足。另一個線程還可以通知任何等待的線程所述條件「可能」被滿足,並且重新檢查該條件。

下面是一個簡單的例子:

public class Exchanger<T> { 
    private T item; 

    public synchronized T poll() { 
     while (item == null) 
      wait(); 
     T result = item; 
     item = null; 
     notifyAll(); 
     return result; 
    } 

    public synchronized void offer(T value) { 
     if (value == null) 
      throw new NullPointerException(); 
     while (item != null) 
      wait(); 
     item = value; 
     notifyAll(); 
    } 
} 

這裏有兩個條件(下一個條件變量,這通常是不很潔淨包裹起來,但):

  • 項槽是空
  • 項槽是不爲空

基本上,只要polloffer被調用,它會阻塞,直到另一個線程分別執行offerpoll。要測試何時阻止,它會在while循環中執行相關檢查。

4

如果您想通過對餐廳建模來學習多線程,請嘗試使用此模型;

  1. 有一個Restaurant類。請注意,一家餐廳不是Runnable,因爲餐廳本身並沒有做任何事情(它裏面的人都這麼做)。而餐廳則包含其他「真正做到」的類。

  2. Waiter類。服務員應定期(例如每1分鐘)爲等待訂購的顧客檢查餐廳。如果它發現想要訂購的客戶會創建訂單並將其添加到訂單隊列中。您的餐廳可以包含多個Waiter實例。

  3. Chef類。廚師訂購服務員寫入的訂單隊列。無論何時創建新訂單,主廚都會下訂單(這需要一些時間,例如2分鐘),然後提醒任何免費服務員。服務員然後爲客戶提供食物。您的餐廳可以容納多個Chef實例。

  4. 有一個Customer類。顧客應該隨機訪問餐廳。他們等待服務員採取他們的命令,等待食物到達,吃食物然後離開。對於獎勵積分,給你的餐廳一個容量,讓客戶離開/讓他們等待滿的時候。在本例中使用

概念

  • 多線程 - 您的餐廳有很多線程,每個人(服務員,顧客和廚師)將在自己的線程中運行。
  • 同步 - 你需要不同的線程(確保兩個侍者不會在同一時間接待顧客
  • 生產者/消費者問題之間同步。 - 訂單隊列是生產者/消費者問題的一個例子
  • 資源匱乏 - 廚師可以烹飪食物,但可能沒有可用的服務員將其服務給客戶。
  • 死鎖 - 如果您給訂單隊列設置最大尺寸,那麼如果隊列滿了,您可能會遇到死鎖。侍者正在等待加入隊伍,而你的廚師正在等待免費服務員爲食物服務。
+0

一個組織良好的概念,但並沒有真正回答有關死鎖的問題。 – 2011-06-18 00:19:06