1

类中的 Finalize 方法ThreadPoolExecutor如下所示。

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

}

在这种情况下,至少 JVM 在这种情况下可能退出shutdownNow是更好的选择。shutdown

更新:

finalize为什么调用方法的唯一可能解释shutdown是,如果程序员没有显式调用它,它将被调用,而 GC 作为一种防御机制。我发现这种机制存在缺陷,因为在上述情况下,JVM 不会被终止。

4

3 回答 3

4

首先,让我问你一个问题:为什么需要池化一个永不终止的线程?您汇集对象以重用它们。

java之所以调用shutdown,是为了给线程一个优雅终止的机会。

如果你需要在一个无限循环中运行一个线程,那么你的线程应该检查Thread.currentThread().isInterrupted()返回 false,然后从run().

在您展示的示例中,您可能希望使用offer()带有超时的方法,而不是和put()

在最坏的情况下,您可以扩展ThreadPoolExecutor并调用shutdownNow()终结器。

于 2012-09-22T16:00:36.030 回答
2

这个故事的寓意是,如果你想关闭一个 ThreadPool,你不应该依赖 finalize 来完成它。Java 中的任何资源都是如此,您永远不应该依赖终结机制(因为它可能永远不会运行)。如果你想关闭一个线程池,你应该自己管理它。

finalize 方法中的shutdown()调用是一个合理的折衷方案,以防程序员“不小心”失去对 ThreadPool 的跟踪。当前任务将运行完成,然后池将关闭。如果shutdownNow()被使用,在某个随机时间点(取决于 gc),您的任务将被中断。可能不太理想。而且,您始终可以创建一个拒绝关闭的任务,无论是否shutdown()shutdownNow()调用(只需while(true)在示例中的 try/catch 块周围添加一个循环)。

于 2012-09-22T16:15:04.713 回答
0

shutdown()被调用时,这意味着池将不会接受新任务,并且在提交的任务完成后实际上会“关闭”。对于您的情况,您最好在shutdownNow()您想要的地方显式调用。

于 2012-09-22T16:05:42.173 回答