【发布时间】:2013-05-29 01:27:42
【问题描述】:
我对 wait() 方法的一个特定用例感到困惑。
根据 javadoc,当以下情况之一发生时,等待应该结束:
- 另一个线程调用 notify 或 notifyAll(好的,有关 notify 的详细信息,请参见 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!");
}
}
【问题讨论】:
-
你怎么知道
notify没有被调用?你假设因为你没有调用notifyAll,所以它不能被调用。但这是一个完全虚假的假设。 -
因为如果它被调用,它应该被记录在案,因为这将是类合同的一个非常重要的部分。如果我不能依赖实现者(在这种情况下是一个自动的)声明在一个非常具体的情况下它将调用 notify() 的事实,那么我将永远不会信任除我创建的类之外的任何类。
-
对于一个您无法控制其实现的对象,您不能依赖等待/通知的语义,因为实现可能需要等待某事并因为某事而通知。
-
显然,Sun 使用 synchronized(thread) 来实现 thread.join() 是一个错误。我亲眼见过很多让人们感到困惑的案例。 Sun/Oracle 一定收到了很多关于它的抱怨,所以他们终于把它记下来了。但是 thread.join() 并不是写那个笔记的好地方。
标签: java multithreading