在以下代码中:
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()线程死亡时它也会被停止 . 但是,我得到的输出如下:退出主方法1 | work |
请为我澄清这个问题 .
经过多次执行该程序后,我观察到以下不同的输出:
没有Thread.sleep(1000):
退出主方法2
退出主方法1 | work |
退出主方法2 | work |
使用Thread.sleep(1000):
退出主方法2 | work |
退出main方法
注意没有sleep()方法的第一个输出 . |工作|没有打印,但线程计数显示为2.这是否意味着main()线程执行在Thread.activeCount()之后但在| work |之前结束打印?在第三个输出中,似乎main()在执行这两个语句后结束 .
现在,我从未期望Thread.activeCount()为2,因为守护程序线程工作者在用户线程main()上加入,这意味着当执行Thread.activeCount()时,只有工作线程而没有main( )线程 .
3 回答
我不知道VM如何知道最后一个非守护程序线程何时停止运行的具体细节,但我可以想象两个解决方案:
后台定期轮询以查看所有非守护程序线程是否已退出(我怀疑这是否是实际解决方案)
后台线程加入所有非deamon线程,并在所有连接返回后退出VM
在这两种情况下,竞争条件是可能的,并且守护程序线程有时有时间在主线程死亡之后执行一些操作,有时不会 .
我执行了几次你的代码,有时在主线程退出后打印一些东西,有时候不会,这证实了我的理论 .
当我在
t.join()
之后添加Thread.sleep(100L)
调用时,除了"Exit from main method"之外不会打印任何内容 .另请注意,如果查看VM中运行的线程列表(例如使用调试器),其中一个名为“DestroyJavaVM” . 鉴于名称,我猜这是一个线程,一旦最后一个非守护程序线程停止运行,它就会与剩余的守护程序线程同时退出JVM .
你如何运行你的代码?
当我从命令行运行你的例子时我得到:退出main方法1 | work |
我猜你可能没有得到
activeCount
和|work|
打印出来,因为JVM可以在所有非守护程序线程终止时停止守护程序线程(这里唯一的一个是main
线程) . 满足该条件时,JVM将终止剩余的守护程序线程并退出 .Thread javadoc says:
终止这些线程可能需要一些时间,因此您的守护程序线程可能有机会执行更多指令 . 当我在打印
activeCount
后添加Thread.sleep(1000)
时,仍会打印activeCount
,但|work|
不是 .让我首先尝试回答输出
没有Thread.sleep(1000)
退出main方法2 - 您必须记住您的Worker线程是守护进程,因此JVM不会等待它完成执行 . 只关心完成主线程执行是非守护进程 . 现在你得到这个输出,因为主线程显示“从主方法退出”,同时工作线程运行并显示2但不幸的是主线程完成,JVM没有等待工作线程(作为守护进程)因此没有显示“工作” .
退出主方法1 | work | - 这里有与上面相同的解释B U T Worker 线程很幸运..有足够的时间来显示'| work |'在JVM完成主线程之前,赶紧退出 .
退出主方法2 | work | - 与之前的解释相同...不确定为什么活动计数有时会返回2,有时会返回1 .
您可以使用类似的逻辑来得出结论
使用Thread.sleep(1000)逻辑 .
提示:您也可以查看状态带有语句System.out.println的线程t(“status of t:”t.getState());就在t.join()....之前你会得到许多终结......这证明了作为NON DAEMON的主线程已经终止所以没有加入工作的问题......太晚了......