-1

My code is shown below, it has two Runnable class: Cook(producer) and Waiter(consumer).

Cook will go to work when the number of meal less than 5,
waiter will go to work when the number of meal more than 0.

It runs properly but cannot stop.
I put a exec.shutdown() in the end of my code, but nothing happened.
If I replace it with exec.shutdownNow(), it will throw 2 InterruptedException when trying to sleep. After that, the program is still running.

How can I stop it?
Is my code a proper way to "simulate" the ProducerConsumer situation?(this is my first try on concurrency)

package com.imooc;

import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

class Meal {
    private final int id;

    Meal(int id) {
        this.id = id;
    }

    public String toString() {
        return "Meal: " + id;
    }
}

class Cook implements Runnable {
    private LinkedList<Meal> mealList;
    private static int count;

    Cook(LinkedList<Meal> mealList) {
        this.mealList = mealList;
    }

    public void run() {
        while (!Thread.interrupted()) {
            synchronized (mealList) {
                while (mealList.size() < 5) {
                    System.out.print("Cook is cooking meal:");
                    System.out.println(++count);
                    mealList.add(new Meal(count));
                    try {
                        TimeUnit.MILLISECONDS.sleep(200);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
                mealList.notifyAll();
                while (mealList.size() == 5) {
                    System.out.println("Cook is waiting");
                    try {
                        mealList.wait();
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            }
        }
        System.out.println("Cook is off-duty");
    }
}

class Waiter implements Runnable {
    private LinkedList<Meal> mealList;

    Waiter(LinkedList<Meal> mealList) {
        this.mealList = mealList;
    }

    public void run() {
        while (!Thread.interrupted()) {
            synchronized (mealList) {
                while (mealList.size() > 0) {
                    System.out.println("Waiter is taking this meal:" + mealList.getLast());
                    mealList.removeLast();
                    try {
                        TimeUnit.MILLISECONDS.sleep(200);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
                mealList.notifyAll();
                while (mealList.size() == 0) {
                    System.out.println("Waiter is waiting");
                    try {
                        mealList.wait();
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            }
        }
        System.out.println("Waiter is off-duty");
    }
}

public class Manager {

    public static void main(String args[]) {
        LinkedList<Meal> mealList = new LinkedList<Meal>();
        ExecutorService exec = Executors.newCachedThreadPool();
        exec.execute(new Waiter(mealList));
        exec.execute(new Cook(mealList));
        exec.execute(new Waiter(mealList));
        exec.execute(new Waiter(mealList));
        exec.execute(new Cook(mealList));
        exec.shutdown();
    }

}

Output screenshot here:
enter image description here

Tom Leung
  • 334
  • 5
  • 18
  • similar question here :http://stackoverflow.com/a/10961760/6523232. You need to properly terminate Threads. Read doc too : https://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html – N0un Nov 18 '16 at 13:33
  • Your code doesn't work as you describe it. In your code the cook will always cook 5 meals before the waiter does anything. Likewise the cook will wait until the waiter serves all 5 meals. In a real world situation this would reduce throughput, since one of the threads would **always** be waiting, regardless of the meal situation. – Kayaman Nov 18 '16 at 13:33
  • Maybe this can help you: [How to stop a thread created by implementing runnable interface?](http://stackoverflow.com/questions/10630737/how-to-stop-a-thread-created-by-implementing-runnable-interface#10630837) – Aleksandar G Nov 18 '16 at 13:39

1 Answers1

2

First, exec.shutdown() only means that the executor won't accept new tasks. If you want to cancel existing tasks, you need to call exec.shutdownNow().

Secondly, catching an InterruptedException resets the interrupted flag of the thread, and your while(!Thread.interrupted()) will not work as expected.

Finally, even if you reset the interrupted flag with Thread.currentThread().interrupt() after catching the exception, the various while conditions (e.g. while (mealList.size() < 5) may still be false and you will loop forever without ever reaching the line where you check for interruption.

assylias
  • 321,522
  • 82
  • 660
  • 783
  • Finally I stop my threads by surrounding run() methods with try-catch, just like what Thinking in Java does. Is it a correct way? – Tom Leung Nov 18 '16 at 14:32