在下面的例子中,由于主线程没有收到子线程的通知,它应该永远等待。但是主线程正在执行,下面示例的输出是:
c
l
total: 19900
为什么要执行主线程?
public class ThreadX extends Thread {
static int total = 0;
public void run() {
synchronized (this) {
for (int i = 0; i < 200; i++) {
total = total + i;
}
System.out.println("c");
}
}
public static void main(String[] args) throws InterruptedException {
ThreadX t = new ThreadX();
t.start();
synchronized (t) {
t.wait();
System.out.println("l");
}
System.out.println("total: " + total);
}
}
对问题主体的回答
查看Thread#join(long)
:
[…]当线程终止时,会调用
this.notifyAll
方法。[…]
请注意,Thread#join()
使用0
调用该函数,这意味着永远。
〔…〕超时0意味着永远等待。
因此,在您的情况下,t
在终止时只调用notifyAll
,这会通知正在等待t
的主线程。
这种非直觉行为是他们在文档中编写以下内容的原因:
建议应用程序不要在
Thread
实例上使用wait
、notify
或notifyAll
。
问题标题的答案
查看Object#wait
(或JLS(17.2.1。等待(:
线程可以在不被通知、中断或超时的情况下唤醒,这就是所谓的虚假唤醒。虽然这种情况在实践中很少发生,但应用程序必须通过测试本应导致线程被唤醒的条件来防范这种情况,如果条件不满足,则继续等待。
因此Java中的线程可以随时唤醒。虚假唤醒的可能性不大,但它可能会发生。