15

我正在寻找线程的一些谜题,但我无法弄清楚为什么以下内容始终打印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打印结果而不是“卡住”等待?

4

6 回答 6

13

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

此实现使用以 this.isAlive 为条件的 this.wait 调用循环。当线程终止时,将调用 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();
}

这个程序打印什么?

于 2012-07-23T09:33:34.483 回答
3

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

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

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

于 2012-07-23T09:14:35.003 回答
3

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


这种行为的原因是,“某人”在notifyAll内部调用。这个“某人”是 JVM 本身,您可以在此处的 C 源代码中“看到”:

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

在第 1531 行,该方法ensure_join调用notifyAll. wait这是调用的对应物java.lang.Thread#join(如 Marko 和其他人所指出的)。

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


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

于 2012-07-23T09:28:57.403 回答
2

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

于 2012-07-23T09:20:50.133 回答
0

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

于 2012-07-23T09:17:18.907 回答
-1

嗯....notify 用于提前通知等待锁定对象的线程。如果您不使用 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() ...锁只会在你做完所有事情后释放..

于 2012-07-23T09:16:43.133 回答