当main()线程执行结束时,为什么连接到main()线程的守护程序线程不会死?

时间:2015-05-04 10:59:19

标签: java multithreading join daemon

在下面的代码中:

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()线程。

2 个答案:

答案 0 :(得分:2)

我不知道VM如何知道最后一个非守护程序线程何时停止运行的具体细节,但我可以想象两个解决方案:

  • 后台定期轮询以查看所有非守护程序线程是否已退出(我怀疑这是否是实际解决方案)
  • 后台线程加入所有非deamon线程,并在所有连接返回后退出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已经终止所以没有加入工作的问题...... 太晚了......