如果在Thread上调用java wait(),则该方法也会在run()方法终止时退出

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

  • 另一个线程调用notify或notifyAll(好的,请参阅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!"); } } 

自Java 7以来,在join()方法的文档中记录了它 :

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

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

一个常见的Java益智游戏是错过使用扩展Thread的类。

BTW虽然使用wait()/ notify()已经老了9年多了,但你仍然可以在极少数情况下使用它们。 如果这样做,您应该更改notify()块中某些内容的状态,并在wait()时等待该状态更改。 这是因为如果你在等待之前调用notify,它就会丢失并且wait()可能会伪造,即使你没有扩展线程。

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