首页 文章

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

提问于
浏览
3

在以下代码中:

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 回答

  • 0

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

    • 后台定期轮询以查看所有非守护程序线程是否已退出(我怀疑这是否是实际解决方案)

    • 后台线程加入所有非deamon线程,并在所有连接返回后退出VM

    在这两种情况下,竞争条件是可能的,并且守护程序线程有时有时间在主线程死亡之后执行一些操作,有时不会 .

    我执行了几次你的代码,有时在主线程退出后打印一些东西,有时候不会,这证实了我的理论 .

    当我在 t.join() 之后添加 Thread.sleep(100L) 调用时,除了"Exit from main method"之外不会打印任何内容 .

    另请注意,如果查看VM中运行的线程列表(例如使用调试器),其中一个名为“DestroyJavaVM” . 鉴于名称,我猜这是一个线程,一旦最后一个非守护程序线程停止运行,它就会与剩余的守护程序线程同时退出JVM .

  • 2

    你如何运行你的代码?

    当我从命令行运行你的例子时我得到:退出main方法1 | work |

    我猜你可能没有得到 activeCount|work| 打印出来,因为JVM可以在所有非守护程序线程终止时停止守护程序线程(这里唯一的一个是 main 线程) . 满足该条件时,JVM将终止剩余的守护程序线程并退出 .

    Thread javadoc says:

    Java虚拟机继续执行线程,直到发生以下任一情况:已调用类Runtime的exit方法,并且安全管理器已允许执行退出操作 . 所有非守护程序线程的线程都已死亡,无论是通过从run方法调用返回还是抛出传播超出run方法的异常 .

    终止这些线程可能需要一些时间,因此您的守护程序线程可能有机会执行更多指令 . 当我在打印 activeCount 后添加 Thread.sleep(1000) 时,仍会打印 activeCount ,但 |work| 不是 .

  • 0

    让我首先尝试回答输出

    没有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的主线程已经终止所以没有加入工作的问题......太晚了......

相关问题