我正在研究多线程并尝试编写程序。
我编写了一个餐厅程序,模拟并行为多个顾客提供服务:
- 一家餐厅开业,创建一名服务员、一名厨师和一些顾客,并等待所有顾客都吃完饭
- 顾客下了订单,等待他的 boolean 值“吃过”变为真,然后通知餐厅
- 服务员等待顾客下单,然后通知厨师
- 厨师等待服务员通知他有关订单的信息,准备餐点并将顾客的“已吃”设置为 true
不知何故,我的程序将以大致不同的结果终止。
经过我的研究,我可以看到以不同方式终止的两个原因:1)如果我的方法不同步(我的程序中不是这种情况)。 2)因为我们无法影响线程的资源分配方式,但这反而会导致线程顺序出现一些细微的差异
但是我的程序终止时存在很大的差异,而不仅仅是线程序列中的小差异:
- 如果有一个客户,它总是正确终止
- 如果有多名顾客,有时一切正常,餐厅就会关门。但有时,在服务员第二次通知后,此时厨师应该收到下一个订单,它就会卡住。它不会终止,线程正在运行,但厨师只是不处理下一个订单。
有人可以给我一些建议吗?
厨师代码:
class Chef extends Thread{
private static int _id=1;
private int id;
Order order;
public Chef(){
this.id=_id;
_id++;
order=null;
this.start();
}
@Override
public void run() {
System.out.println("Chef ("+id+") starts to work...");
synchronized(this){
while(order==null){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
System.out.println("Chef ("+id+") prepared Order ("+this.order.getId()+")");
Restaurant.customers.get(this.order.getId()-1).served=true;
synchronized(Restaurant.customers.get(this.order.getId()-1)){
Restaurant.customers.get(this.order.getId()-1).notify();
}
order=null;
}
public void prepareOrder(Order order){
this.order=order;
System.out.println("Chef ("+this.id+") prepares order ("+order.getId()+")");
synchronized(this){
this.notify();
}
}
}
服务员代码(工作正常,始终处理收到的订单):
class Waiter extends Thread{
private static int _id=1;
private int id;
Order order;
public Waiter(){
this.id=_id;
_id++;
order=null;
this.start();
}
@Override
public void run() {
System.out.println("Waiter ("+this.id+") starts to work...");
synchronized(this){
while(takenOrder==false){
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
order=null;
Restaurant.chefs.get(0).prepareOrder(order);
}
public void takeOrder(Order order){
this.order=order;
System.out.println("Waiter ("+this.id+") takes order ("+this.order.getId()+")");
synchronized(this){
this.notify();
}
}
}
最佳答案
答案问题是这样的
synchronized(this){
...
}
上面的代码不正确有两个原因。
- 不存在相互排斥。每个线程都有自己的监视器/锁。你的锁可以被它自己的线程看到。因此synchronized(this)是多余的。
- 您永远不应该在 Thread 实例上进行同步(不好的做法)。在你的情况下,这是 Thread 的实例。 还有一件事不要扩展线程,尽量避免使用 Runnable 代替
如何解决?
class Chef implments Runnable {
private Object lock;
Chef(Object lock) {
this.lock = lock;
}
public run() {
synchronized(lock) {
// do stuff here
}
}
}
class Waiter implments Runnable {
private Object lock;
Chef(Object lock) {
this.lock = lock;
}
public run() {
synchronized(lock) {
// do stuff here
}
}
}
//your main
public static void main(String []args) {
Object obj = new Object();
Thread chef = new Thread(new Chef(obj));
Thread waiter = new Thread(new Waiter(obj));
chef.start();
waiter.start();
}
建议的上述方法是两个线程之间互斥的非常基本的示例。 但这不是最好的方法。尝试使用 BlockingQueue 它可能最适合您的目的
即不是共享互斥对象而是共享 ArrayBlockingQueue 实例。它将照顾 如果订单队列为空或客户队列已满,许多类似的事情都会等待
关于java - 多线程:为什么我的程序终止时有不同的结果?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17645662/