运行 Java 中 main() 中的线程实例上的 wait()

Running wait() on a Thread instance from within main() in Java

我在 java.lang.Object 中使用定时版本的 wait() 并观察到它在两种不同情况下的行为不同。

场景1:在Thread

中使用运行()的默认定义
public static void main (String[] args) throws InterruptedException {
    Thread t = new Thread();    
    t.start();
    System.out.print("X");
    synchronized(t) { t.wait(10000);}
    System.out.print("Y");
}

关于场景 1 的问题: 我遇到 X 和 Y 之间的延迟。这是因为我正在从 main 调用 wait() (即使在 t 上),因此正在使用主线程的调用堆栈,而不是第二个线程的调用堆栈?

场景 2: 即时子类化线程以覆盖 运行() 以打印某些内容。

public static void main (String[] args) throws InterruptedException {
     Thread t = new Thread() {public void run() 
                     {System.out.print("I am the second thread.");}};
     t.start();
     System.out.print("X");
     synchronized(t) { t.wait(10000);}
     System.out.print("Y");
}

关于场景 2 的问题: 我没有遇到任何延迟!仅仅因为我覆盖了 运行() 就发生了什么变化?现在,每次我 运行 程序时,它都会立即打印 "XI am the second thread.Y",没有任何延迟! wait()的效果去哪儿了?

您实际上已经 运行 了解为什么您永远不应该在 Thread 上调用 waitnotify(All)(请参阅 Thread 的 JavaDocs)。在内部,Thread 使用 wait 和 notifyAll 来实现 Thread.join(),所以在第二种情况下发生的是你的线程进入等待,但随后另一个线程死掉并调用 notifyAll(),这唤醒了你的主线程。

如果你只想等待一个经过的时间,使用Thread.sleep,如果你真的想等待线程的终止,使用Thread.join。此外,请阅读 Object 中的 javadoc,以正确使用 waitnotifynotifyAll

javaDoc:

public final void join(long millis)
                throws InterruptedException

Waits at most millis milliseconds for this thread to die. A timeout of 0 means to wait forever. This implementation uses a loop of this.wait calls conditioned on this.isAlive. As a thread terminates the this.notifyAll method is invoked. It is recommended that applications not use wait, notify, or notifyAll on Thread instances.

相关且正确,我 +1。我将尝试添加一些信息,说明为什么这是相关的。

当你打电话时

synchronized(t) { t.wait(10000);}

在主线程中,是主线程在做等待。 t 是主线程正在等待的监视器。您期望这会使您的 t 线程进入休眠状态是错误的。

这里的monitor(被锁定的共享对象,刚好是t)用于不同线程之间的通信,一个线程在monitor上调用notifyAll,其他线程在monitor上等待收到通知。您可以将监视器视为共享通信点。

在您的第一个示例中,线程 t 立即启动并结束(因为它没有任何事情要做)。线程在主线程开始等待之前完成并发送通知,因此您会看到等待超时之前的延迟。

在第二个例子中,线程 t 有东西要打印,它和主线程之间存在竞争条件。这是一场混战,先发生什么取决于时间的偶然性。你看到的是线程 t 现在必须向控制台打印一行,所以它设法保持忙碌足够长的时间,以至于在主线程开始等待时它仍然存在,允许主线程在 t 完成时接收通知,导致主线程缩短等待时间。