2

我对 wait() 方法的特定用例感到困惑。
根据 javadoc,当以下情况之一发生时,等待应该结束:

  • 另一个线程调用 notify 或 notifyAll (好的,有关 notify 的详细信息,请参见 javadoc,但这与此问题无关)
  • 另一个线程中断这个(等待)线程
  • 超时过期(如果使用带超时的等待版本)

在我等待的对象本身是线程的情况下,即使没有调用 notify(),也会发生 wait() 退出,并且上述条件都不成立。但它发生在 Thread.run() 方法结束时。虽然这种行为可能有意义,但它不应该记录在 Thread javadoc 中吗?我也觉得它很混乱,因为它与 join() 行为重叠。

这是我的测试代码:

public static class WorkerThread extends Thread {

    @Override public void run() {

        try{
           System.out.println("WT: waiting 4 seconds");
           Thread.sleep(4000);

           synchronized (this) {
            notify();
           }

           System.out.println("WT: waiting for 4 seconds again");
           Thread.sleep(4000);
           System.out.println("WT: exiting");

        } catch (InterruptedException ignore) {
            ignore.printStackTrace();
        }

    }

}

public static void main (String [] args) throws InterruptedException {

    WorkerThread w = new WorkerThread();

    w.start();

    synchronized(w) {
        w.wait();
        System.out.println("MT: The object has been notified by the thread!");
    }

    synchronized(w) {

        w.wait(); //THIS FINISHES WITHOUT notify(), interrupt() OR TIMEOUT!

        System.out.println("MT: The thread has been notified again!");
    }

}
4

3 回答 3

7

从 Java 7 开始,在join() 方法的文档中记录了它

当线程终止时,将调用 this.notifyAll 方法。建议应用程序不要在 Thread 实例上使用 wait、notify 或 notifyAll。

于 2013-06-02T21:41:41.340 回答
5

直接扩展 Thread 是一种常见的反模式。问题是您可能会产生各种意想不到的后果,因为 Thread 是一个复杂的类。它所做的一件事是在线程停止时通知线程尝试加入()线程。这具有通知任何在该线程对象上等待的线程的效果。

一个常见的 Java 难题是错过使用扩展 Thread 的类。

顺便说一句,虽然使用 wait()/notify() 已经超过 9 年了,但您仍然可以在极少数情况下使用它们。如果你这样做了,你应该在 notify() 块中改变某些东西的状态,并在你 wait() 时等待状态改变。这是因为如果您在等待之前调用 notify,它会丢失并且 wait() 可能会虚假存在,即使您不扩展线程也是如此。

于 2013-06-02T21:41:42.637 回答
1

如果您想要可预测和可控的等待/通知行为,请在线程和等待它的方法之间共享一个对象。

于 2013-06-02T22:32:11.737 回答