我写了一个应该永远不会停止的测试应用。问题t.wait()
(t
是Thread
对象),但我从不调用通知。为什么这段代码会结束?
尽管t
上的主线程正在同步,但是生成的线程会运行,因此它不会锁定此对象。
public class ThreadWait {
public static void main(String sArgs[]) throws InterruptedException {
System.out.println("hello");
Thread t = new MyThread();
synchronized (t) {
t.start();
Thread.sleep(5000);
t.wait();
java.lang.System.out.println("main done");
}
}
}
class MyThread extends Thread {
public void run() {
for (int i = 1; i <= 5; i++) {
java.lang.System.out.println("" + i);
try {
Thread.sleep(500);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
}
结果是主线程等待5秒钟,在此期间工作人员给出其输出。然后在5秒钟结束后,程序退出。 t.wait()
不等待。如果主线程不会休眠5秒(注释这一行),那么t.wait()
实际上会等到工作完成。当然,join()
是一种在这里使用的方法,但是,出乎意料的是,wait()
与join()
做同样的事情。为什么呢?
也许JVM看到了,因为只有一个线程正在运行,所以没有机会通知主线程并解决死锁。如果这是真的,它是一个记录的功能吗?
我正在使用Windows XP,Java 6进行测试。
答案 0 :(得分:10)
您正在等待Thread
- 虽然大多数对象未被隐式通知,但在线程终止时会通知Thread
对象。它记录在某处(我正在寻找它......)你应该不在wait
对象上使用notify
/ Thread
,因为这是在内部完成的。
这是一个很好的例子,说明为什么最好使用“私有”对象进行同步(以及等待/通知) - 只有 你的代码知道的东西。我通常使用类似的东西:
private final Object lock = new Object();
(但是,一般情况下,如果可以的话,使用java.util.concurrent提供的一些更高级别的抽象会更清晰。如评论中所述,实现Runnable
而不是实现Thread
也是一个好主意。自己延长{{1}}。)
答案 1 :(得分:8)
wait
的{{3}}给出了答案:虚假的唤醒是可能的。这意味着JVM可以随时结束对wait
的调用。
如果您不想要这个(可能总是如此),文档甚至会为您提供解决方案:将调用wait
置于循环中并检查您等待的条件是否已成为真实的每次醒来。