在执行器服务上调度的守护进程线程;解释为什么这是不好的形式

我对在用;也就是说,调用 或 将导致池中创建的线程正常退出。如果他们响应你,可以确定最终等将被调用,你会得到一个干净的,可预测的退出(在那里你可以清理任何资源等)。ExectuorServiceshutdownshutdownNowinterrupt

但是,如果您已将线程设置为守护程序(通过执行程序),如下所示。ThreadFactory

ExecutorService pool = Executors.newSingleThreadExecutor(new ThreadFactory() {
   @Override
   public Thread newThread(Runnable runnable) {
      Thread thread = Executors.defaultThreadFactory().newThread(runnable);
      thread.setDaemon(true);
      return thread;
   }
});

主线程终止后,VM 将突然终止任何守护程序线程。在上面的示例中,调度然后突然终止的(守护进程)线程将绕过任何最终块,并且任何可中断的方法都不会抛出DistrutheatedException

因此,我倾向于认为将 池中使用的线程标记为守护程序是不好的做法......我的问题实际上是帮助我说出为什么ThreadPoolExecutor

为什么在执行器服务的线程池中使用守护程序线程是不可取的做法(或者如果你不同意的话不是)?特别是,我对描述虚拟机关闭与正常关闭(具有中断策略且运行良好的线程)与守护程序线程的生命周期感兴趣。

扩展最后一点,on 将调用自身,但是当它使用守护程序线程时,如果 VM 调用了它们,它们可能已经终止了。那么线程池的行为是什么呢?如果底层线程突然终止,它是否会被诱骗以保持活动状态(因此不会退出 VM)?finalizeThreadPoolExecutorshutdownfinalize

我问这个问题的部分原因是因为我已经看到它被用来绕过关闭实际ExectorService的需要。您能想到绕过关闭生命周期可能会产生不良影响的场景吗?到目前为止,我能想到使用守护进程的唯一原因是走捷径,我想了解它可能造成的任何意想不到的副作用。


答案 1

在执行器服务的线程池中使用守护程序线程是不是不好的做法?

如果发送到该特定任务的任务可以突然终止,那么为什么不这样做,这就是守护进程线程所做的。但一般来说,没有多少任务可以在没有关机仪式的情况下终止,所以如果你选择守护进程线程,你必须知道你在做什么。ExecutorService

finalize()在即将对对象进行垃圾回收时调用。不保证任何特定对象何时(如果有的话)将是GCD,也不例外,因此可以或可能不会调用它。该行为取决于特定的 JRE 实现,即使使用相同的实现,也可能不时变化。ThreadPoolExecutorfinalize()


答案 2

守护进程线程可能很有用,如果它们没有突然终止,它们就不会那么有用IMO。

据推测,我们可以想象另一种类型的线程,当没有正常线程不再运行时,它们会中断,而不是突然终止。这可能有点方便,但是如果您必须进行任何清理,则很可能您想要进行有序清理。这将限制此功能的便利性。

另一方面,如果您有在关机时不需要任何清理的任务,那么deamon线程非常方便。而且您不想浪费时间等待它们达到某个特定状态或冒着停机等挂起的风险,因为您使用deamon线程的原因是因为您不需要任何类型的清理。如果应用程序正在关闭,则执行任何内容都是浪费时间。如果你在乎,那么你不应该使用deamon线程。

这与 deamon 线程池没有什么不同。如果该线程池正在执行在关机时不需要任何清理的任务,那么由于方便起见,这将是有意义的。

摘自JCiP一书

应谨慎使用守护程序线程,以便随时安全地放弃处理活动,而无需清理。特别是,将守护程序线程用于可能执行任何类型 I/O 的任务是很危险的。最好将守护程序线程保存为“内务管理”任务,例如,定期从内存中缓存中删除过期条目的后台线程。


推荐