I have the following problem that uses java concurrency.
There are 3 clients and the cooker in a restaurant. All of them change information through 2 lists. One list for placing the orders, and another list for placing the meals. The customer sends the order to the order list, and the cooker reads it. The cooker sends the prepared meal to the customer on the meals list. I implemented the cooker and the customer as threads that deal with the 2 lists. The goal of this problem is to synchronize access to the lists. Unfortunately, the sequence of wait()
and notifyAll()
between threads are not good, and I am not getting what is the problem. My code is below. Can anyone point me what is wrong with the code?
Edit
The problem is that the client and the cooker hangs without consuming all meals, as we can see from the output.
Tony: Client orders.
Tony: The meal is still not ready.
Cooker: Cooking Fish soup for Tony
Cooker: The cooker will serve the meal Fish soup for Tony
Cooker: Waiting for orders to cook.
Restaurant.java
import java.util.ArrayList;
import java.util.List;
public class Restaurant
{
public static void main(String[] args)
{
List<Order> orderQueue = new ArrayList<>();
List<Dish> dishesQueue = new ArrayList<>();
// Client 1
String clientName1 = "Tony";
List<Order> personalOrders = new ArrayList<>();
personalOrders.add(new Order(clientName1, "Fish soup"));
personalOrders.add(new Order(clientName1, "Duck rice"));
personalOrders.add(new Order(clientName1, "Coffee"));
personalOrders.add(new Order(clientName1, "Pudding"));
Thread tclient1 = new Thread(new Client(personalOrders, orderQueue, dishesQueue), clientName1);
// Client 2
String clientName2 = "John";
personalOrders = new ArrayList<>();
personalOrders.add(new Order(clientName2, "Stew"));
personalOrders.add(new Order(clientName2, "Cake"));
Thread tclient2 = new Thread(new Client(personalOrders, orderQueue, dishesQueue), clientName2);
// Client 3
String clientName3 = "Mike";
personalOrders = new ArrayList<>();
personalOrders.add(new Order(clientName3, "Hotdog"));
personalOrders.add(new Order(clientName3, "Coffee"));
Thread tclient3 = new Thread(new Client(personalOrders, orderQueue, dishesQueue), clientName3);
Thread tCooker = new Thread(new Chef(orderQueue, dishesQueue), "Cooker");
tclient1.start();
tclient2.start();
tclient3.start();
tCooker.start();
}
}
Chef.java
import java.util.List;
class Chef implements Runnable
{
private final List<Order> orders;
private final List<Dish> dishes;
public Chef(List<Order> sharedOrders, List<Dish> sharedDishes)
{
this.orders = sharedOrders;
this.dishes = sharedDishes;
}
@Override
public void run()
{
while (true)
{
try
{
Order order = cook();
serve(order);
}
catch (InterruptedException ex)
{
ex.printStackTrace();
}
}
}
private Order cook() throws InterruptedException {
Order order = null;
synchronized (orders) {
if (orders.isEmpty()) {
System.out.println(Thread.currentThread().getName() + ":\t Waiting for orders to cook.");
Thread.sleep(1000);
orders.wait();
} else {
order = orders.remove(0);
System.out.println(Thread.currentThread().getName() + ":\t Cooking " + order.getDish() + " for " + order.getClientName());
orders.notifyAll();
}
}
return order;
}
private void serve(Order order) throws InterruptedException
{
synchronized (dishes)
{
if (dishes.isEmpty()) {
System.out.println(Thread.currentThread().getName() + ":\t The cooker is waiting for more requests");
dishes.wait();
}
// else {
Thread.sleep(1000);
Dish meal = new Dish(order.getClientName(), order.getDish());
System.out.println(Thread.currentThread().getName() + ":\t The cooker will serve the meal " + meal.getDish() + " for " + meal.getClientName());
dishes.add(meal);
dishes.notifyAll();
// }
}
}
}
Client.java
import java.util.Collections;
import java.util.List;
class Client implements Runnable
{
private final List<Order> orders;
private final List<Order> personalOrders;
private final List<Dish> dishes;
public Client(List<Order> personalOrders, List<Order> orders, List<Dish> dishes)
{
this.personalOrders = personalOrders;
this.orders = orders;
this.dishes = dishes;
}
@Override
public void run()
{
while (!personalOrders.isEmpty())
{
try
{
request(getPersonalOrders().remove(0));
consume();
} catch (InterruptedException ex)
{
ex.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + ":\t Acabou de comer.");
}
private void request(Order order) throws InterruptedException {
synchronized (orders) {
System.out.println(Thread.currentThread().getName() + ":\t Cliente faz pedido");
orders.add(order);
Thread.sleep(1000);
orders.notifyAll();
}
}
private void consume() throws InterruptedException
{
synchronized (dishes)
{
if (dishes.isEmpty())
{
System.out.println(Thread.currentThread().getName() + ":\t The meal is still not ready.");
dishes.wait();
}
// else {
Thread.sleep(1000);
Dish meal = dishes.remove(0);
System.out.println(Thread.currentThread().getName() + ":\t " + meal.getClientName() + " ready to eat " + meal.getDish());
dishes.notifyAll();
// }
}
}
public List<Order> getPersonalOrders() {
return personalOrders;
}
}