Java是否隐式通知等待线程?

时间:2012-01-27 08:12:05

标签: java multithreading

我写了一个应该永远不会停止的测试应用。问题t.wait()tThread对象),但我从不调用通知。为什么这段代码会结束? 尽管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进行测试。

2 个答案:

答案 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置于循环中并检查您等待的条件是否已成为真实的每次醒来。