-1

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;
   }
}


xeon123
  • 819
  • 1
  • 10
  • 25
  • can you tell me what is your problem? I mean why do you think your code is not working properly? – Amit Tiwary Oct 19 '19 at 19:33
  • Sounds like a "producer-consumer" problem. The _cooker_ cannot produce a meal before he has received an order, correct? Have you tried searching the Internet for "producer consumer java" ? – Abra Oct 19 '19 at 20:11

1 Answers1

1

This statement:

this.dishes = Collections.synchronizedList(dishes);

makes this.dishes a different object than dishes. synchronize and notify on one of those objects won't affect the other object.

That's why your clients are never notified about dishes ready.

Piotr Praszmo
  • 17,928
  • 1
  • 57
  • 65