在下面的代码中:
class Worker extends Thread {
Thread t;
public Worker(Thread thread) {
t=thread;
}
public void run() {
try {
t.join();
} catch(InterruptedException e) {
System.out.println("Exception is thrown and caught");
}
System.out.println(Thread.activeCount());
System.out.print("|work|");
}
public static void main(String[] args) {
Thread t=Thread.currentThread();
Worker worker = new Worker(t);
worker.setDaemon(true);
worker.start();
System.out.println("Exit from main method");
}
}
由于worker是一个在main()线程上加入的守护线程,| work |永远不应该打印,因为用户线程main()首先完成,并且由于worker是一个守护程序线程,所以当main()线程死亡时它也会被停止。 但是,我得到的输出如下: 退出main方法 1 |工作|
请为我澄清这个问题。
在多次执行该程序后,我观察到以下不同的输出:
没有Thread.sleep(1000):
退出main方法 2
退出main方法 1 |工作|
退出main方法 2 |工作|
使用Thread.sleep(1000):
退出main方法 2 |工作|
退出主要方法
注意没有sleep()方法的第一个输出。 |工作|没有打印,但线程计数显示为2.这是否意味着main()线程执行在Thread.activeCount()之后但在| work |之前结束打印?在第三个输出中,似乎main()在执行这两个语句后结束。
现在,我从未期望Thread.activeCount()为2,因为守护程序线程工作者在用户线程main()上加入,这意味着当执行Thread.activeCount()时,只会有工作线程和没有main()线程。
答案 0 :(得分:2)
我不知道VM如何知道最后一个非守护程序线程何时停止运行的具体细节,但我可以想象两个解决方案:
在这两种情况下,竞争条件是可能的,并且守护程序线程有时有时间在主线程死亡后执行一些操作,有时不会。
我执行了几次代码,有时会在主线程退出后打印,有时也不会打印,这证实了我的理论。
当我在Thread.sleep(100L)
之后添加t.join()
来电时,除了&#34之外不会打印任何内容;退出主要方法"。
另请注意,如果查看VM中运行的线程列表(例如使用调试器),其中一个命名为" DestroyJavaVM"。鉴于名称,我猜这是一个线程,一旦最后一个非守护程序线程停止运行,它将与剩余的守护程序线程同时退出JVM。
答案 1 :(得分:0)
让我先尝试回答
的输出没有Thread.sleep(1000)
从main方法2退出 - 你必须记住你的Worker线程是一个守护进程,所以JVM不会等待它完成它的执行。只关心完成主线程执行是非守护进程。 现在你得到这个输出因为"退出主要方法"主线程显示并在此期间工作线程运行并显示2但不幸的是主线程已完成且JVM没有等待工作线程(作为守护进程)因此工作'没有显示。
退出主方法1 | work | - 这里有与上面相同的解释 B U T工人线程很幸运..有足够的时间来展示' |工作|' 在JVM完成主线程之前,赶紧离开它。
退出主方法2 | work | - 与之前的解释相同......不确定 关于为什么活动计数有时返回2和有时返回1的原因。
您可以使用类似的逻辑来得出
的结论使用Thread.sleep(1000)逻辑。
提示:您也可以使用statement检查线程t的状态 System.out.println(" t的状态:" + t.getState());就在此之前 t.join()....你会得到TERMINATED很多......这证明了主线程 这是非DAEMON已经终止所以没有加入工作的问题...... 太晚了......