I'm doing some research on multithreading and trying to write programs.
I've written a restaurant program, simulating serving multiple customers in parallel:
- a restaurant opens, creates a waiter, a chef, some customers and waits until all customers have eaten their meals
- a customer makes an order, and waits for his boolean 'eaten' to become true, then he notifies the restaurant
- the waiter waits for a client to make an order, and then notifies the chef
- the chef waits for the waiter to notify him about the order, prepares the meal and sets customer's 'eaten' on true
Somehow my program will terminate with roughly different results.
After research I've done, I can see 2 reasons for terminating differently: 1) if my methods are not synchronized (which isn't the case in my program). 2) because we can't influence the way resources for threads are allocated, but this would rather cause some minor differences in the sequence of threads
But my program terminates with big differences, not just small differences in the sequence of threads:
- if there is one customer, it always terminates correctly
- if there are multiple customers, sometimes everything goes correctly and the restaurant closes. but sometimes it gets stuck after the second notification by the waiter, at the moment, when the chef should receive the next order. and it does not terminate, the threads are running, but the chef just does not process the next order.
Could someone give me any tips?
code for chef:
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();
}
}
}
code for waiter (works correctly, always proceeds incoming orders):
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();
}
}
}