为什么多次调用wait()不会抛出异常?

时间:2016-09-11 19:07:46

标签: java multithreading wait

我知道调用wait()方法而不获取对象的所有权会导致异常。 和来自Java doc,调用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();
                }
            }

        }

    }
}

1 个答案:

答案 0 :(得分:4)

如果你只运行那个线程,它会在等待之后阻塞(尝试添加一个调试输出)。

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

修改:每次更新问题

因此,&#34;两次调用wait()而不通知&#34;是不可能的,因为对wait()的第一次调用将阻止该线程,直到通知为止。它不能在循环中被称为无限次,它会阻塞或抛出异常。

<强>增加:

顺便说一句,有一个&#34;裸体&#34;等待通常是有风险的,因为不能保证唤醒哪些等待线程(例如,生产者或消费者)。 一个常见的习语(如Java&#34;内置监视器&#34; - synchronized块 - 没有条件变量)就像是

while(! condition)
    wait();

在这种情况下,对于消费者来说,或许类似

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