Не могу решить задачу по wait/notify
Начал изучать wait/notify, решаю следующую задачу, которую следует решить при помощи wait/notify.
Есть следующие потоки: повар ,официантка и посетители, число посетителей задано параметром. Каждого посетителя нужно накормить обедом из 3 блюд. Повар готовит 1 блюдо, официантка берет его и относит 1 посетителю , затем (случайным образом) повар либо готовит 2 блюдо и оно относится официанткой 1 клиенту, либо повар готовит 1 блюдо для 2 клиента. В следующий раз повар уже может приготовить либо 1 блюдо для нового клиента( если остались клиенты) , либо очередное блюдо, которое еще не получал предыдущий клиент. Но если например 2 клиента ждут второе блюдо, то первым его должен получить клиент с меньшим номером. Если клиент не получил еще второе блюдо, то он не может получить третье блюдо. Выводить номер блюда вместе с именем "повар" или "официантка" или "клиент" с номером клиента в зависимости от того , кто работает в данный момент времени. Работа потоков заканчивается, когда всех посетителей обслужили.
Выбор поваром блюда для готовки немного упростил, вряд ли это сильно меняет суть задачи.
Вот мой код:
import java.util.ArrayList;
import java.util.List;
public class Main {
// Есть следующие потоки: повар ,официантка и посетители, число посетителей задано параметром. Каждого посетителя нужно накормить обедом из 3 блюд.
// Повар готовит 1 блюдо, официантка берет его и относит 1 посетителю , затем (случайным образом) повар либо готовит 2 блюдо и оно относится официанткой 1 клиенту,
// либо повар готовит 1 блюдо для 2 клиента.
// В следующий раз повар уже может приготовить либо 1 блюдо для нового клиента( если остались клиенты) , либо очередное блюдо, которое еще не получал предыдущий клиент. Но если
// например 2 клиента ждут второе блюдо, то первым его должен получить клиент с меньшим номером. Если клиент не получил еще второе блюдо, то он не может получить третье блюдо.
// Выводить номер блюда вместе с именем "повар" или "официантка" или "клиент" с номером клиента в зависимости от того , кто работает в данный момент времени.
// Использовать ограничения из задания 3. Работа потоков заканчивается, когда всех посетителей обслужили
public static void main(String[] args) {
cafe();
}
public static void cafe () {
Cafe cafe = new Cafe();
Officiant officiant = new Officiant(cafe);
Cook cook = new Cook(cafe);
List<Customer> customers = new ArrayList<>();
cafe.customers = customers;
for (int i = 0; i < 10; i++) {
Customer customer = new Customer(cafe, "Customer "+i);
customers.add(customer);
}
for (Customer customer : customers) {
new Thread(customer).start();
System.out.println(customer.name + " вошел");
}
new Thread(cook).start();
new Thread(officiant).start();
}
static class Cafe {
Integer currentDishType = null; // 1 or 2 or 3
Integer currentCustomerIndex = null;
List<Customer> customers;
Integer lastCookedDish;
public synchronized void eat (Customer customer) {
try {
while (!(currentCustomerIndex != null && currentCustomerIndex == customers.indexOf(this) && currentDishType != null)) {
System.out.println(customer.name+" ждет");
wait();
}
if (currentDishType == 1)
customer.eaten1 = true;
else if (currentDishType == 2)
customer.eaten2 = true;
else if (currentDishType == 3)
customer.eaten3 = true;
System.out.println("["+customer.name+"] Текущее блюдо "+currentDishType);
System.out.println("["+customer.name+"] Текущий клиент "+currentCustomerIndex);
System.out.println(customer.name + " сьел блюдо " + currentDishType);
currentDishType = null;
currentCustomerIndex = null;
if (customer.eaten3) {
customers.remove(this);
System.out.println(customer.name + " покинул кафе");
}
notify();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
private synchronized void deliver () {
try {
while (currentCustomerIndex != null || currentDishType == null) {
System.out.println("Официант ждет");
wait();
}
int customerIndex = 0;
for (Customer customer : customers) {
if (currentDishType == 1 && !customer.eaten1)
break;
else if (currentDishType == 2 && !customer.eaten2)
break;
else if (currentDishType == 3 && !customer.eaten3)
break;
customerIndex++;
}
currentCustomerIndex = customerIndex;
System.out.println("[Официант] Текущее блюдо "+currentDishType);
System.out.println("[Официант] Текущий клиент "+currentCustomerIndex);
System.out.println(
"[Официант] Официант отнес блюдо " + currentDishType + " посетителю " + customers.get(currentCustomerIndex).name
);
notify();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
private synchronized void cook () {
try {
while (currentCustomerIndex != null || currentDishType != null) {
System.out.println("Повар ждет");
wait();
}
int dish;
if (lastCookedDish == null)
dish = 1;
else if (lastCookedDish == 3)
dish = 1;
else
dish = lastCookedDish + 1;
lastCookedDish = dish;
currentDishType = dish;
System.out.println("[Повар] Текущее блюдо "+currentDishType);
System.out.println("[Повар] Текущий клиент "+currentCustomerIndex);
System.out.println("[Повар] Повар испек блюдо " + dish);
notify();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
static class Customer implements Runnable {
boolean eaten1 = false;
boolean eaten2 = false;
boolean eaten3 = false;
Cafe cafe;
String name;
Customer (Cafe cafe, String name) {
this.cafe = cafe;
this.name = name;
}
@Override
public void run() {
while (cafe.customers.contains(this)) {
cafe.eat(this);
}
System.out.println("thread "+name+" finished");
}
}
static class Officiant implements Runnable {
Cafe cafe;
Officiant (Cafe cafe) {
this.cafe = cafe;
}
@Override
public void run() {
while (!cafe.customers.isEmpty()) {
cafe.deliver();
}
System.out.println("thread officiant finished");
}
}
static class Cook implements Runnable {
Cafe cafe;
public Cook(Cafe cafe) {
this.cafe = cafe;
}
@Override
public void run() {
while (!cafe.customers.isEmpty()) {
cafe.cook();
}
System.out.println("thread cook finished");
}
}
}
У меня не сформировалось пока четкого понимания работы wait/notify, поэтому моя ошибка может быть очевидной. Подскажите, пожалуйста, что не так.