2

我的问题是我的关机发生得太早了,没有等待进程自行清理。

但是,如果在我的关闭线程中添加一个while(true) Thread.sleep(1000);,则该过程可以很好地清理,并且显然永远不会关闭。

这让我很困惑,因为关闭在许多非守护线程完成之前完成。例如,如果我编写了一个非常简单的测试程序,其中没有main()无限循环和关闭线程,main无论如何都会终止(没有任何来自捕获InterruptedExceptions 的异常跟踪)。

据我所知,关闭线程run方法完成时会发生关闭。我认为根据这些知识,我可以通过在轮询循环中结束它来解决这个问题,轮询Future表示成功关闭其余进程的 a 。但这似乎是错误的——我真的只想等待所有非守护线程关闭,而且我当然不想进行投票。

  1. 当关闭钩子的线程方法完成时,我是否正确关闭run完成?
  2. 什么是执行关机的好习惯方法,等待我的实际关机任务完成?
4

2 回答 2

2

通常,Java 进程可以在所有非守护线程终止后停止。这通常是 VM 将调用关闭挂钩的时间。

如果您终止进程或调用,挂钩将被提前调用(即仍然存在一些非守护线程)System.exit()

如果我理解正确,您会在所有其他非守护线程完成后尝试做某事(即等待所有其他关闭线程完成)。

这并不容易实现。您可以尝试的是访问根ThreadGroup(它没有父级,使用Thread.currentThread().getGroup()然后向上移动)。所有线程都是该组(或其子组)的子组。

所以你可以遍历这棵树,直到只剩下守护线程:

int maxWait = 100;
while(countNonDaemonThreads() > 0 && --maxWait > 0) {
    Thread.sleep(100);
}

这应该可以,但我还没有测试过。请注意,您需要小心关闭线程中的代码;它不能阻塞,您必须以某种方式处理所有错误,否则 VM 可能无法正确终止。

编辑The code in 中的代码java.lang.Shutdown是单线程的,因此如果其中一个关闭挂钩阻塞,则整个 VM 挂起。

现在回答你的问题:

  1. halt()VM 在被调用时终止。这是最后一件事Terminate.run(),所以是的,VM应该run(). 我什至认为run()永远不会回来。可能有错误和本机代码可能会阻碍,但这就是它应该的样子。

  2. 一个好的做法是使用线程池来完成您的工作并等待它们完成。关闭挂钩是最后的手段。由于您无法真正影响顺序,并且您无法确定非守护线程是否仍然存在,因此对于“最后关灯”类型的工作来说,它们是脆弱的。

    使用线程池,您可以拥有多个独立于它们的线程池,您可以清楚地定义如何关闭池以及如何等待它们完成。最重要的是,您可以以可以中止它们的方式构建线程。当您处于关闭钩子中并且一个非守护线程拒绝死亡时,您要做什么?使用线程池,您将知道可能在其中的线程类型以及简单终止它的风险。

于 2013-07-10T15:57:47.097 回答
1

当关闭钩子的线程的运行方法完成时,我是否正确关闭完成?什么是执行关机的好习惯方法,等待我的实际关机任务完成?

使您的关闭线程成为非守护进程

如果这还不够,您的代码中有一个错误。你可以向自己证明一个不退出的关闭钩子不会被提前杀死。

于 2013-07-10T15:24:27.627 回答