I wrote program which simulates the work of the restaurant. It works but I would like to change it because I think there is better solution.Thanks for your suggestions.
Client.java
public class Client implements Runnable {
private Restaurant r;
public void makeOrder() throws InterruptedException {
synchronized (r) {
r.notifyAll();
System.out.println("Start ordering ");
Thread.sleep(1000);
r.putOrderMadeByClient(r.orderId);
System.out.println("End ordering ");
while(r.orderReceived==false)
r.wait();
r.getOrderReceived();
}
}
public Client(Restaurant r) {
this.r=r;
}
public void run() {
try {
makeOrder();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Waiter.java
public class Waiter implements Runnable {
private Restaurant r;
public void makeServe() throws InterruptedException {
synchronized (r) {
r.notifyAll();
while(r.orderMadeByClient==false)
r.wait();
System.out.println("Start serving order ");
Thread.sleep(1000);
r.putOrder(r.getOrderMadeByClient());
while(r.orderReady==false)
r.wait();
r.putOrderReceived(r.getFood());
System.out.println("End serving order ");
}
}
public Waiter(Restaurant r) {
this.r=r;
}
@Override
public void run() {
try {
makeServe();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Chef.java
public class Chef implements Runnable {
private Restaurant r;
public void makeFood() throws InterruptedException {
synchronized (r) {
r.notifyAll();
while(r.orderTaken==false)
r.wait();
System.out.println("Start making food ");
Thread.sleep(1000);
r.putFood(r.getOrder());
System.out.println("End making food ");
}
}
public Chef(Restaurant r) {
this.r=r;
}
@Override
public void run() {
try {
makeFood();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Restaurant.java
public class Restaurant {
boolean orderMadeByClient;
boolean orderTaken;
boolean orderReady;
boolean orderReceived;
long orderId;
public Restaurant() {
}
public void makeRestaurant() {
Client cl = new Client(this);
Chef ch = new Chef(this);
Waiter w = new Waiter(this);
Thread t1 = new Thread(cl);
Thread t2 = new Thread(w);
Thread t3 = new Thread(ch);
t1.start();
t2.start();
t3.start();
}
synchronized long getOrderMadeByClient() {
while (!orderMadeByClient) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
orderMadeByClient = false;
notifyAll();
System.out.println("get order from client #" + orderId);
return orderId;
}
synchronized void putOrderMadeByClient(long l) {
while (orderMadeByClient) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
orderMadeByClient = true;
this.orderId = l;
notifyAll();
System.out.println("put order client #" + l);
}
synchronized long getOrder() {
while (!orderTaken) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
orderTaken = false;
notifyAll();
System.out.println("get order from waiter #" + orderId);
return orderId;
}
synchronized void putOrder(long l) {
while (orderTaken) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
orderTaken = true;
this.orderId = l;
notifyAll();
System.out.println("put order to cook #" + l);
}
synchronized long getFood() {
while (!orderReady) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
orderReady = false;
notifyAll();
System.out.println("get order by waiter #" + orderId);
return orderId;
}
synchronized void putFood(long n) {
while (orderReady) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
orderReady = true;
this.orderId = n;
notifyAll();
System.out.println("put order by cook #" + n);
}
synchronized long getOrderReceived() {
while (!orderReceived) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
orderReceived = false;
notifyAll();
System.out.println("get order by client #" + orderId);
return orderId;
}
synchronized void putOrderReceived(long l) {
while (orderReceived) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
orderReceived = true;
this.orderId = l;
notifyAll();
System.out.println("put order by waiter #" + l);
}
}
Main.java
public class Main {
public static void main(String[] args) {
Restaurant r=new Restaurant();
r.makeRestaurant();
}
}
-
\$\begingroup\$ There is very similar demo example [code.google.com/p/wing-ding/source/browse/trunk/books/…. It was written using scala and actor concurrency model, but suggests much readable way to do things you are trying to do. Detailed description of that code could be found there: programming-scala.labs.oreilly.com/ch09.html. \$\endgroup\$CheatEx– CheatEx2011年06月20日 07:53:12 +00:00Commented Jun 20, 2011 at 7:53
1 Answer 1
The main issue here is that everything synchronizes on the restaurant object. This means that the chef cannot prepare food while the client is placing an order, waiters cannot serve while the chef is cooking, etc. The first step would be to add BlockingQueue
s to Restaurant
and let them manage all of the calls to wait()
and notify()
for you.
You'd need one queue of orders that waiters place and chefs take and another for food that chefs place and waiters take. When a Chef
calls take()
on the order queue, it will block until there is an order available. A Waiter
calling offer()
on the same queue will block until there is room in the queue. You can make the queues bounded (maximum size) or unbounded.
You might even create a queue to hold the client
s waiting to place orders. Waiter
s would poll()
the food and client queues in their run()
loop so they don't wait forever for food to be ready when they haven't even placed any orders yet.
public void run() {
while (true) {
Food f = foodQueue.poll(2, TimeUnit.SECONDS);
if (f != null) {
// deliver food to client...
}
Order o = clientQueue.poll(2, TimeUnit.SECONDS);
if (o != null) {
if (!orderQueue.offer(o, 120, TimeUnit.SECONDS)) {
// kitchen is too busy!
break; // waiter quits out of frustration
}
}
}
}
The Chef
class currently waits for a second and then takes the order and makes the food available immediately. Instead, it should take the order, then wait, and finally make the food available. If you were to create a queue for the use of the chef while cooking, you could use a priority queue (orders the elements in the queue) and have different types of food take different lengths of time to prepare. The chef would then have multiple things cooking at once and deliver each after its own cook time has expired.
With the above in place you could really kick this into high gear by creating multiple waiters and chefs and add a separate thread that randomly creates clients that place random orders.