为什么ThreadPoolExecutor finalize调用shutdown而不是shutdownNow

时间:2012-09-22 15:50:49

标签: java executorservice

课程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();

}

在这种情况下,shutdownNowshutdown更好的选择,至少JVM可能已经退出。

更新

只有finalize调用shutdown方法的原因的唯一可能解释是,如果程序员没有明确地调用它,那么当GC作为防御机制时它将被调用。我看到了这种机制的缺陷,因为在上面的情况下JVM不会被终止。

3 个答案:

答案 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()