在ExecutorService上安排的守护程序线程; 解释为什么这是不好的forms
我对使用ExectuorService
安排的线程有序关闭的想法很满意; 也就是说,调用shutdown
或shutdownNow
将导致池上创建的线程正常退出。 如果他们响应interrupt
你可以确定最终会被调用等等,你将得到一个干净,可预测的退出(你可以清理任何资源等)。
但是,如果您已将线程设置为守护程序(通过执行程序的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将突然终止任何守护程序线程。 在上面的示例中,调度然后突然终止的(守护程序)线程将绕过任何finally块,并且任何可中断的方法都不会抛出InterruptedException
。
所以,我倾向于认为将ThreadPoolExecutor
使用的线程标记为守护进程是不好的做法……我的问题是关于帮助我发声的原因 。
为什么在ExecutorService
的线程池中使用守护程序线程是不好的做法(或者如果你不同意)? 特别是我有兴趣通过正常关闭(具有中断策略并且运行良好的线程)与守护程序线程来描述VM关闭的生命周期。
扩展最后一点,在ThreadPoolExecutor
上finalize
将自己调用shutdown
,但是当它使用守护进程线程时,如果VM调用了finalize
,它们可能已经终止。 那么线程池的行为是什么? 如果底层线程突然终止,它是否可以被欺骗以保持活动状态(因此不会退出VM)?
我问的部分原因是因为我已经看到它曾经绕过了关闭实际的ExectorService的需要。 您能想到绕过其关闭生命周期会产生不良影响的情况吗? 到目前为止,我能够提出使用守护进程的唯一原因是采取捷径,我想欣赏它可能导致的任何意外的副作用。
在ExecutorService的线程池中使用守护程序线程是不好的做法吗?
如果发送到特定ExecutorService
的任务可以突然终止,那么为什么不,这就是守护程序线程所做的。 但通常情况下,没有很多任务可以在没有关闭仪式的情况下终止,因此如果您选择守护程序线程,您必须知道自己在做什么。
当一个对象即将被垃圾收集时调用finalize()
。 无论何时,如果有任何特定对象都是GCd,并且ThreadPoolExecutor
也不例外,则无法保证,因此可以调用或不调用其finalize()
。 行为取决于特定的JRE实现,即使具有相同的实现,也可能随时变化。
我倾向于为守护进程和非守护进程线程使用不同的池。 守护进程池往往会执行重复清理作业,监视和后台任务,如果一个或两个未执行则无关紧要。 任何只在应用程序仍在运行时才有意义的任务都可以创建一个守护程序线程任务。 例如,GC线程是守护程序线程。
守护程序线程可能很有用,如果它们没有突然终止,它们就不会那么有用IMO。
据推测,我们可以想象另一种类型的线程,当没有正常的线程运行时它会被中断,而不是突然终止。 这可能有点方便,但如果你不得不做任何清理,你很可能想要有条不紊地清理。 这会限制此function的便利性。
另一方面,如果你有任务在关机时不需要任何清理,那么deamon线程非常方便。 并且你不想浪费时间等待他们到达某个特定的状态或冒着停机等等的风险,因为你使用deamon线程的原因是因为你不需要任何类型的清理。 如果应用程序执行任何操作都是浪费时间。 正在关闭。 如果你关心,那么你不应该使用deamon线程。
它与deamon线程池没有什么不同。 如果该线程池正在执行在关闭时不需要任何清理的任务,那么由于方便起见,这将是有意义的。
来自JCiP书 :
应该谨慎使用守护程序线程,可以在没有清理的情况下随时安全地放弃处理活动。 特别是,将守护程序线程用于可能执行任何类型I / O的任务是危险的。 守护程序线程最好保存用于“内务”任务,例如后台线程定期从内存缓存中删除过期的条目