【问题标题】:Will notify interrupt the sleeping thread?会通知中断睡眠线程吗?
【发布时间】:2019-05-24 06:01:45
【问题描述】:

我已经实现了生产者和消费者的经典示例。这里生产者将在生产 value = 0 后休眠 10 秒 [不会等待状态,因为队列大小小于 10 ]。消费者将消费value =0 并通知生产者将休眠一秒

所以我的问题是,为什么消费者的通知没有中断生产者线程并打印Producer Exception cached

下面程序的输出是这样的:

Producer add value=0
Consumer consumes value=0

(等待 10 秒)

Producer add value=1
Consumer consumes value=1

(等待 10 秒)

Producer add value=2
Consumer consumes value=2

生产者和消费者的经典例子。

public class ClassicalProducerConsumer{
    public static void main(String[] args) {
        Buffer  buffer = new Buffer(3);
        Thread producer = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    int value = 0;
                    while (true) {
                        buffer.add(value);
                        value++;
                        Thread.sleep(10000); // Make producer wait for 10 seconds.
                    }
                }catch (Exception ex){
                    System.out.println("Producer Exception cached");
                    ex.printStackTrace();
                }
            }
        });

        Thread consumer = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    while (true) {
                        int value = buffer.poll();
                        Thread.sleep(1000);
                    }
                } catch (InterruptedException e) {
                    System.out.println("Consumer Exception cached");
                    e.printStackTrace();
                }
            }
        });
        producer.start();
        consumer.start();
    }
}

class Buffer{
    Queue<Integer> queue;
    int size;

    public Buffer(int size) {
        this.size = size;
        queue = new LinkedList<>();
    }
    public void add(int value) throws InterruptedException {
        synchronized (this){
            while (queue.size() >=size){
                wait();
            }
            System.out.println("Producer add value="+ value);
            queue.add(value);
            notify();
        }
    }
    public int poll() throws InterruptedException {
        synchronized (this){
            while (queue.size()==0){
                wait();
            }
            int value = queue.poll();
            System.out.println("Consumer consumes value="+ value);
            notify();
            return value;
        }
    }
}

【问题讨论】:

  • notifyinterrupt 是两种不同的机制。
  • 因为可能有多个线程在等待这样的生产者/消费者问题,所以我通常更喜欢使用notifyAll(),以确保任何可能的线程不会被饿死或错过。

标签: java multithreading producer-consumer java.util.concurrent


【解决方案1】:

正如@RealSkeptic 提到的notify() 与中断无关。在要中断的线程上调用 interrupt()。然后这个线程中的任何阻塞方法都会通过抛出Interrupted exception来返回控制。建议通过在catch块中调用Thread.currentThread().interrupt()来恢复线程的中断状态。

【讨论】:

  • 中断状态无需恢复。这是一条经常重复但毫无用处的建议。
  • @JohnKugelman 如果我需要稍后在代码中检查线程是否被中断怎么办?
  • @JohnKugelman Brian Goetz 在他的“实践中的并发”一书中说,有两种方法可以处理中断 - 将其传播到堆栈的更高层或恢复它。由于 Thread 的 'run()' 不允许传播,我们需要恢复它
  • 我并不是要争论,我对中断的想法真的值得他们自己的博客文章,或者可能是一个独立的问答。我认为 API 文档在解释应该如何使用中断以及它们的用途方面做得很差。您可以保留中断标志并且您可以在不清除它的情况下检查它,但两者都不是必需的。 API 文档应该提倡简单地捕获InterruptedException,并在极少数情况下检查interrupted()。它应该不鼓励致电isInterrupted()。清除中断标志是正常的,也是意料之中的。
  • 最重要的是,它应该解释谁实际调用了interrupt() 并触发了中断:它始终是您自己的代码!除非您自己是应用程序编写者,否则不会发生中断。如果您自己不致电interrupt(),您的线程将永远不会被中断。 InterruptedException 是一个受检异常,这是一个 API 缺陷。在我们打电话给sleep() 的任何时候都被要求抓住它是一个错误。我们大多数人不会打断自己的线程;我们的睡眠电话永远不会被打断。我们需要处理永远不会发生的异常!呃。
猜你喜欢
  • 1970-01-01
  • 2013-05-29
  • 1970-01-01
  • 2011-05-14
  • 2012-12-22
  • 1970-01-01
  • 1970-01-01
  • 2018-08-09
  • 1970-01-01
相关资源
最近更新 更多