使用Poison Pill无法阻止生产者/消费者线程

时间:2013-03-18 23:47:19

标签: java multithreading thread-safety interrupt

我有非常简单的代码,它使用“Poison Pill”模拟生产者/消费者停止技术。

我有Producer类:

public class Producer extends Thread {

    private final BlockingQueue<String> queue;

    public Producer(BlockingQueue<String> queue) {
        this.queue = queue;
    }

    @Override
    public void run() {
        try {
        while (true) {
                //unblocking this line will cause the code to stop after intrrupt               
                //System.out.println("1");
                queue.put("hello world");
            }
        } catch (InterruptedException e) {
                try {
                    queue.put(Main.POISON_PILL);
                } catch (InterruptedException e1) {
                }
            }
        }
}

消费者类:

public class Consumer extends Thread {

    private final BlockingQueue<String> queue;

    public Consumer(BlockingQueue<String> queue) {
        this.queue = queue;
    }

    @Override
    public void run() {
        try {
            while (true) {
                String s = queue.take();
                if (s.equals(Main.POISON_PILL))
                    break;
                else
                    System.out.println(s);
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
}

现在主要功能:

public static String POISON_PILL = "POISON_PILL";

    public static void main(String[] args) {

        BlockingQueue<String> queue = new LinkedBlockingQueue<String>();
        Producer producer = new Producer(queue);
        Consumer consumer = new Consumer(queue);
        producer.start();
        consumer.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {

        } finally {
            producer.interrupt();
        }
    }

即使在producer.interrupt()调用之后,还有未知原因, “你好世界”永远在控制台中打印。

我无法理解的第二件事是,为什么取消注释System.out.println("1");会导致程序在生产者线程中断后退出。

请帮助我理解原因。

1 个答案:

答案 0 :(得分:4)

我的猜测是你的制作人只是比你的消费者跑得快得多,你出现永远不会用完物品。创建一个没有显式容量的LinkedBlockingQueue会创建一个容量为Integer.MAX_VALUE的容量,这足以让消费者保持打印很长时间。

这也可能是你添加System.out.println行时开始工作的原因;通过要求控制台I / O,它可以使生产者减慢到消费者能够跟上的程度。

尝试创建一个容量较小的LinkedBlockingQueue,例如100左右。