如何在ProducerConsumer情况下停止Java线程?

时间:2016-11-18 13:27:16

标签: java multithreading concurrency

我的代码如下所示,它有两个Runnable类:Cook(生产者)和Waiter(消费者)。

当饭菜数少于5时,库克会去上班,
当用餐人数超过0时服务员会去上班。

它运行正常但无法停止 我在代码的末尾添加了exec.shutdown(),但没有任何反应 如果我将其替换为exec.shutdownNow(),则在尝试睡眠时会抛出2 InterruptedException。之后,该程序仍在运行。

如何阻止它?
我的代码是否是“模拟”ProducerConsumer情况的正确方法?(这是我第一次尝试并发)

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

}

此处输出截图:
enter image description here

1 个答案:

答案 0 :(得分:2)

首先,exec.shutdown()仅表示执行者不接受新任务。如果您要取消现有任务,则需要致电exec.shutdownNow()

其次,捕获InterruptedException会重置线程的中断标记,而while(!Thread.interrupted())将无法按预期工作。

最后,即使你在捕获异常后用Thread.currentThread().interrupt()重置了中断的标志,各种条件(例如while (mealList.size() < 5))可能仍然是假的,你将永远循环而不会到达你所在的行检查是否中断。