是否在线程结束时发出通知? 为什么这个代码示例有效?

我正在寻找线程的一些难题,我无法弄清楚为什么以下一致打印999999

 class Job extends Thread { private Integer number = 0; public void run() { for (int i = 1; i < 1000000; i++) { number++; } } public Integer getNumber() { return number; } } public class Test { public static void main(String[] args) throws InterruptedException { Job thread = new Job(); thread.start(); synchronized (thread) { thread.wait(); } System.out.println(thread.getNumber()); } } 

同一个锁上没有notify (虚假唤醒似乎被忽略)。
如果一个线程完成了一个通知获取信号或什么?
怎么main打印结果而不是“卡住”等待?

在Java 7中的Javadoc Thread.join(长)

此实现使用this.wait调用this.isAlive的循环。 当一个线程终止时,将调用this.notifyAll方法。 建议应用程序不要在Thread实例上使用wait,notify或notifyAll。

直接使用线程这种方式被认为是不实际的。 注意:wait()可能因任何原因而结束,可能是虚假的。


基于与@Voo评论相关的益智游戏。 关键是你不应该使用Thread的内部行为,因为这更容易导致混淆。

 public static String getName() { return "MyProgram"; } public static void main(String... args) { new Thread() { public void run() { System.out.println("My program is " + getName()); } }.start(); } 

这个节目打印什么?

为了澄清,我已将您的代码修改为:

 Job thread = new Job(); thread.start(); final Object lock = new Object(); synchronized (lock) { lock.wait(); } System.out.println(thread.getNumber()); 

现在它阻止了。 这是@Nitram在他的回答中解释的第一手确认。 如果你想看一下 Thread实现代码,那么为什么这是观察到的行为就很明显了。

注意:此答案已经过广泛编辑。


这种行为的原因是,“某人”在内部调用notifyAll 。 这个“某人”是JVM本身,你可以在这里看到C源:

http://hg.openjdk.java.net/jdk7/hotspot/hotspot/file/f95d63e2154a/src/share/vm/runtime/thread.cpp

在第1531行中,方法ensure_join调用notifyAll 。 这与java.lang.Thread#joinwait调用相对应(如Marko和其他人所述)。

ensure_join在方法JavaThread::exit中的第1664行调用JavaThread::exit


由于这是“内部簿记”,没有人应该依赖这种行为。

简单地说,一旦线程执行结束,线程就会通知所有等待的线程。 它不是建议为什么这样做,但它的工作原理。 要在线程结束时进行同步,请使用Thread.join

线程完成后会自动通知线程对象,这就是主线程不会卡住的原因。

嗯….通知用于过早通知等待锁定对象的线程。 如果您不使用Notify,那么当它完成时它会释放锁定。

 So that is equivalent to notify 

不,不是..考虑下面的情况。

 class Job extends Thread { private Integer number = 0; public void run() { synchronized(this) { for (int i = 1; i < 1000000; i++) { number++; } notify(); //releases lock here and your main thread continues do sumthing... do sumthing... } } public Integer getNumber() { return number; } } 

如果你不使用notify()...只有在你做了所有的总结后才会释放锁定。