java 在 ExecutorService 上调度的守护线程;解释为什么这是不好的形式
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7158587/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Daemon threads scheduled on an ExecutorService; explain why this is bad form
提问by Toby
I'm comfortable with the idea of orderly shutdown on threads scheduled with an ExectuorService
; that is to say, calling shutdown
or shutdownNow
will cause threads created on the pool to exit gracefully. If they respond to interrupt
you can be sure finally etc will be called and you'll get a clean, predictable exit (where you can cleanup any resources etc).
我对使用ExectuorService
;调度的线程有序关闭的想法感到满意。也就是说,调用shutdown
或shutdownNow
会导致池上创建的线程优雅退出。如果他们对interrupt
您做出回应,则可以确定最终会调用 etc 并且您将获得干净、可预测的退出(您可以在其中清理任何资源等)。
However, if you've set your thread to be a daemon (via the executor's ThreadFactory
) as below.
但是,如果您已将线程设置为守护进程(通过执行程序的ThreadFactory
),如下所示。
ExecutorService pool = Executors.newSingleThreadExecutor(new ThreadFactory() {
@Override
public Thread newThread(Runnable runnable) {
Thread thread = Executors.defaultThreadFactory().newThread(runnable);
thread.setDaemon(true);
return thread;
}
});
after the main thread terminates, the VM will abruptly terminate any daemon threads. In the example above, a (daemon) thread scheduled and then abruptly terminated will bypass any finally blocks and any interruptable methods won't throw InterruptedException
.
主线程终止后,VM 会突然终止所有守护线程。在上面的例子中,一个(守护进程)线程被调度然后突然终止将绕过任何 finally 块并且任何可中断的方法都不会 throwInterruptedException
。
So, I tend to think that marking the threads used in a ThreadPoolExecutor
's pool as daemon is bad practice... my question is really about helping me vocalise why.
所以,我倾向于认为将 aThreadPoolExecutor
的池中使用的线程标记为守护进程是不好的做法……我的问题实际上是帮助我说出为什么。
Why is it bad practice (or not if you disagree) to use daemon threads in a ExecutorService
's thread pool? In particular I'm interested in describing the life-cycle of the VM shutdown with graceful shutdown (threads that have an interruption policy and play nicely) vs daemon threads.
为什么在 aExecutorService
的线程池中使用守护线程是不好的做法(如果你不同意也不是)?我特别有兴趣描述使用优雅关闭(具有中断策略并且运行良好的线程)与守护线程关闭 VM 的生命周期。
Expanding that last point, finalize
on ThreadPoolExecutor
will call shutdown
on itself, but when it's using daemon threads, they could have terminated already if finalize
was called by the VM. What's the behavior of the thread pool then? Can it be tricked into remaining alive (and so not exiting the VM) if underlying threads terminated abruptly?
扩展最后一点,finalize
onThreadPoolExecutor
将调用shutdown
自身,但是当它使用守护线程时,如果finalize
被 VM 调用,它们可能已经终止。那么线程池的行为是什么?如果底层线程突然终止,它是否可以被欺骗保持活动状态(从而不退出 VM)?
Part of the reason I'm asking is because i've seen it used to bypass the need to shutdown the actual ExectorService. Can you think of scenarios where bypassing itsshutdown life-cycle can have ill affect? So far, the only reason I can come up with for using daemons is to take a short cut and I want to appreciate any unexpected side affects it could cause.
我问的部分原因是因为我已经看到它曾经绕过关闭实际 ExectorService 的需要。您能想到绕过其关闭生命周期会产生不良影响的场景吗?到目前为止,我能想到的使用守护进程的唯一原因是走捷径,我想了解它可能导致的任何意想不到的副作用。
采纳答案by Joonas Pulakka
is it bad practice to use daemon threads in a ExecutorService's thread pool?
在 ExecutorService 的线程池中使用守护线程是不好的做法吗?
If the tasks sent to that particular ExecutorService
are ok to be terminated abruptly, then why not, that's what daemon threads do. But generally, there are not many tasks that are ok to be terminated with no shutdown ceremonies at all, so you must know what you're doing if you opt to daemon threads.
如果发送到该特定任务的任务ExecutorService
可以突然终止,那么为什么不呢,这就是守护线程所做的。但是一般来说,没有多少任务可以在完全没有关闭仪式的情况下终止,所以如果你选择守护线程,你必须知道你在做什么。
finalize()
is called when an object is about to be garbage collected. There are no guarantees on when, if ever, any particular object will be GCd, and ThreadPoolExecutor
is no exception, so its finalize()
may or may not be called. The behavior depends on the particular JRE implementation, and even with the same implementation, may vary from time to time.
finalize()
当对象即将被垃圾回收时调用。无法保证任何特定对象何时(如果有的话)将成为 GCd,ThreadPoolExecutor
也不例外,因此它finalize()
可能会或可能不会被调用。行为取决于特定的 JRE 实现,即使使用相同的实现,也可能会不时变化。
回答by Peter Lawrey
I tend to have different pools for daemon and non-daemon threads. Daemon pools tend to do recurring clean up jobs, monitoring and background tasks which don't matter if one or two is not executed. Any task which is only meaningful while the application is still running is good to make a daemon thread task. e.g. GC threads are daemon threads.
我倾向于为守护进程和非守护进程线程使用不同的池。守护进程池倾向于执行重复的清理作业、监控和后台任务,如果不执行一两个则无关紧要。任何仅在应用程序仍在运行时才有意义的任务都适合制作守护线程任务。例如,GC 线程是守护线程。
回答by Enno Shioji
Daemon threads can be useful, and if they weren't terminated abruptly, they wouldn't be so useful IMO.
守护线程可能很有用,如果它们没有突然终止,IMO 就不会那么有用。
Presumably we could imagine another type of thread, which are interrupted when no normal threads are running anymore, instead of being abruptly terminated. That may be a little convenient, but if you had to do any clean up at all, it's likely that you wanted to do an orderly clean up. This would limit the convenience of this feature.
大概我们可以想象另一种类型的线程,当没有正常线程运行时,它们会被中断,而不是突然终止。这可能有点方便,但如果您必须进行任何清理,很可能您想要进行有序清理。这将限制此功能的便利性。
On the other hand, if you had tasks that would not need any clean up at shutdown, deamon threads are quite convenient. And you wouldn't want to waste time waiting them to arrive at some specific state or risk a hang up on shutdown etc., because the reason you are using a deamon thread is because you don't need any kind of clean up. It would be a waste of time to execute anything if the app. is shutting down. If you care, then you shouldn't have used deamon threads.
另一方面,如果您有在关闭时不需要任何清理的任务,守护线程非常方便。并且您不想浪费时间等待它们到达某个特定状态或冒着关机挂断等风险,因为您使用守护线程的原因是因为您不需要任何类型的清理。如果应用程序执行任何操作都是浪费时间。正在关闭。如果您关心,那么您不应该使用守护线程。
It's no different with deamon thread pools. If that thread pool is doing tasks that do not need any clean up at shutdown, then it would make sense because of the convenience.
与守护线程池没有什么不同。如果该线程池正在执行在关闭时不需要任何清理的任务,那么由于方便,这将是有意义的。
From the JCiP book:
从JCiP 书中:
Daemon threads should be used sparinglyfew processing activities can be safely abandoned at any time with no cleanup. In particular, it is dangerous to use daemon threads for tasks that might perform any sort of I/O. Daemon threads are best saved for "housekeeping" tasks, such as a background thread that periodically removes expired entries from an in-memory cache
应谨慎使用守护线程很少有处理活动可以随时安全地放弃而无需清理。特别是,将守护线程用于可能执行任何类型 I/O 的任务是危险的。守护线程最适合用于“内务管理”任务,例如定期从内存缓存中删除过期条目的后台线程