Не могу решить задачу по wait/notify

Рейтинг: -1Ответов: 1Опубликовано: 16.02.2023

Начал изучать 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, поэтому моя ошибка может быть очевидной. Подскажите, пожалуйста, что не так.

Ответы

Ответов пока нет.