Кажется, что один из моих потоков завершается раньше, чем я ожидал в своем коде потребителя / производителя - PullRequest
0 голосов
/ 25 марта 2019

Так что я пытаюсь сделать простой код производителя / потребителя в Java.Мой продюсер, кажется, работает очень хорошо, однако достигает точки, когда он производит 10 предметов, а затем просто прекращает производство предметов.Затем я должен ждать, пока потребитель удалит 10 элементов, добавленных в массив List, и у меня останется потребитель, которому нечего будет потреблять, поскольку производитель не добавляет в список.

Сначала я подумал, что по какой-то причине в моем классе продюсера код выходит из цикла while, но он никогда не смог этого сделать, поэтому я честно заблудился.Вот мой код

import java.util.Random;

public class Main {


    public static boolean eating = true;
    private static ArrayList<Integer> buffet = new ArrayList<Integer>(10);

    public static void main(String[] args) throws InterruptedException {

        //make our producer
        Thread producerThread = new Thread(new Runnable() {
            @Override
            public void run() {
                producer();
                System.out.println("BUFFET IS CLOSED, NO MORE FOOD TO MAKE");
            }
        });

        //make our consumer
        Thread consumerThread = new Thread(new Runnable() {
            @Override
            public void run() {
                consumer();
            }
        });

        producerThread.start();
        consumerThread.start();

        consumerThread.join();
        producerThread.join();


    }

        private static void producer(){

            Random randomCooking = new Random();

            while(true){
                if(buffet.size() < 10) {
                    System.out.println("Producer added a dish");
                    buffet.add(randomCooking.nextInt(5));
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }




        }

        private static void consumer() {

            Random randomEating = new Random();

            while (true) {
                try {
                    Thread.sleep(500);

                    if (randomEating.nextInt(5) == 0) {

                        if(buffet.size() > 0) {

                            Integer value = buffet.remove(buffet.size() - 1);

                            switch (value) {
                                case 0:
                                    System.out.println("Dish 0: Shrimp & Rice, eaten by consumer! Dishes left: " + buffet.size());
                                    break;
                                case 1:
                                    System.out.println("Dish 1: Mashed Potatoes and Gravey, eaten by consumer! Dishes left: " + buffet.size());
                                    break;
                                case 2:
                                    System.out.println("Dish 2: Spaghetti and Meatballs, eaten by consumer! Dishes left: " + buffet.size());
                                    break;
                                case 3:
                                    System.out.println("Dish 3: Burger & Fries, eaten by consumer! Dishes left: " + buffet.size());
                                    break;
                                case 4:
                                    System.out.println("Dish 4: Salad & Tofu, eaten by consumer! Dishes left: " + buffet.size());
                                    break;

                            }
                        }else{
                            System.out.println("Food is all finished");

                        }

                    }else{
                        System.out.println("consumer decided not to eat! Dishes left: " + buffet.size() );
                    }

                }catch(InterruptedException e){
                    e.printStackTrace();
                }
            }

        }

    }

Через некоторое время это все, что у меня осталось

consumer decided not to eat! Dishes left: 0
consumer decided not to eat! Dishes left: 0
consumer decided not to eat! Dishes left: 0
consumer decided not to eat! Dishes left: 0
Food is all finished
consumer decided not to eat! Dishes left: 0
consumer decided not to eat! Dishes left: 0

1 Ответ

0 голосов
/ 25 марта 2019

ArrayList не подходит для одновременного доступа. Это означает, что если поток изменяет его и несколько потоков обращаются к нему одновременно, он должен быть синхронизирован извне. Самое простое, что вы можете сделать - обернуть его в синхронизированный аналог и синхронизировать доступ к нему:

List<Integer> buffet = Collections.synchronizedList(new ArrayList<>());
...
while (true) {
    synchronized (buffet) {
        // perform your operations
    }
}

Несоблюдение этого совета может привести к недетерминированному поведению - как прямо указано в документации (и, в основном, к тому, что вы наблюдаете).

Однако, как правило, наиболее полезной структурой данных для проблем производитель-потребитель является BlockingQueue. Таким образом, вы можете использовать некоторые из его реализаций, например, ArrayBlockingQueue или LinkedBlockingQueue.

...