2011-06-17 53 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