【问题标题】:Why calling wait() more than once is not throwing Exceptions?为什么多次调用 wait() 不会抛出异常?
【发布时间】:2016-09-11 19:07:45
【问题描述】:

我知道在没有获得对象所有权的情况下调用wait() 方法会导致异常。 和来自 Java 文档,关于调用 wait() 线程 * 释放此监视器的所有权并等待另一个线程 * 通知在这个对象的监视器上等待唤醒的线程 * 通过调用{@code notify} 方法或 * {@code notifyAll} 方法。 所以一旦在对象上调用wait(),该特定线程就会失去对该对象的所有权,直到其他线程通知它。

为什么在没有通知的情况下调用wait() 两次,而不是抛出错误? 为了确保,..我只是运行了生产者,所以我没有其他线程来通知它,wait() 方法被无限次调用。 然而,尽管在第一次 wait() 调用后失去了所有权,但随后的等待调用应该抛出异常。不是吗?但为什么它工作正常?

class Producer extends Thread {

    private Queue<Integer> queue;
    private int maxSize;

    public Producer(Queue<Integer> queue, int maxSize, String name) {
        super(name);
        this.queue = queue;
        this.maxSize = maxSize;
    }

    public void run() {
        while (true) {
            synchronized (queue) {
                try {
                    queue.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        }

    }
}

【问题讨论】:

  • “不止一次”是什么意思?您是否从不同的线程调用上面的run() 方法? (也许它是从您没有向我们展示的某些代码中调用的?)

标签: java multithreading wait


【解决方案1】:

如果您只运行该线程,它将在等待后(中)阻塞(尝试添加调试输出)。

wait() 阻塞直到收到通知,并在返回之前重新获取锁。即,当wait() 在您的示例中返回时,您再次锁定了queue

编辑:每次更新问题

因此,“调用wait() 两次而不通知”是不可能的,因为第一次调用wait() 将阻塞线程直到通知。它不能在循环中被无限次调用,它要么阻塞,要么抛出异常。

加法:

顺便说一句,“裸”等待通常是有风险的,因为无法保证唤醒哪个等待线程(例如,生产者或消费者)。 一个常见的习惯用法(作为 Java“内置监视器”——synchronized 块——没有条件变量)类似于

while(! condition)
    wait();

在这种情况下,对于消费者来说,可能是这样的

while(queue.isEmpty())
    wait();

【讨论】:

  • 如果这回答了你的问题,是的,你没有在这里循环,你调用 wait() 一次然后你的代码停止,直到收到通知或抛出异常。
  • @Sriharsha,如果它回答了您的问题,请接受答案。如果没有,请澄清,我会尝试更新答案。
  • @SRobertz,请更新您的答案,因为它没有指向我的问题,“为什么在没有通知的情况下多次调用 wait() 不会引发异常”,所以有点不清楚。尽管如此,我从 cmets 那里得到了一点,它不是在循环,它只是在等待收到通知。所以疑问被澄清了
  • 您写道“wait() 方法被无限次调用。这不应该发生。您是否验证过它是否与例如调试打印输出有关?如果是这样,您需要显示更多代码,因为那不应该发生。
  • @SRobertz,是的。谢谢 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-28
  • 2013-09-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多