课程ThreadPoolExecutor
中的Finalize方法如下所示。
protected void finalize() {
shutdown();
}
考虑以下程序,其中线程永远不会终止
ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.submit(new Runnable() {
@Override
public void run() {
try {
new SynchronousQueue<String>()
.put("will never get removed");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
executorService = null;
System.gc();
}
在这种情况下,shutdownNow
比shutdown
更好的选择,至少JVM可能已经退出。
更新
只有finalize
调用shutdown
方法的原因的唯一可能解释是,如果程序员没有明确地调用它,那么当GC作为防御机制时它将被调用。我看到了这种机制的缺陷,因为在上面的情况下JVM不会被终止。
答案 0 :(得分:4)
首先,让我问你一个问题:为什么你需要汇集一个永不终止的线程?您将对象池化以重用它们。
java调用shutdown的原因是为线程提供优雅终止的机会。
如果你需要在无限循环中运行一个线程,那么你的线程应检查Thread.currentThread().isInterrupted()
是否为false,然后从run()
返回。
在您显示的示例中,您可能希望使用方法offer()
并使用超时,而不是put()
。
Wost case情景,您可以延长ThreadPoolExecutor
并在终结器中调用shutdownNow()
。
答案 1 :(得分:2)
这个故事的寓意是,如果你想要一个ThreadPool关闭,你不应该依赖于finalize来做到这一点。对于Java中的任何资源都是如此,您应该从不依赖于终结机制(因为它可能从不运行)。如果你想让ThreadPool关闭,你应该自己管理它。
在程序员“意外地”失去对ThreadPool的跟踪的情况下,finalize方法中的shutdown()
调用是合理的妥协。当前任务将运行完成,然后池将关闭。如果使用shutdownNow()
,则在某个随机时间点(取决于gc),您的任务将被中断。可能不太理想。并且,无论是否调用shutdown()
或shutdownNow()
,您都可以始终创建拒绝关闭的任务(只需在try / catch周围添加while(true)
循环在你的例子中阻止。)
答案 2 :(得分:0)
调用shutdown()
时,表示池将不接受新任务,并且在提交的任务完成后实际上将“关闭”。对于您的情况,您最好明确地在某个地方调用shutdownNow()
。