为什么这个线程池不被垃圾收集?
在这个代码示例中,ExecutorService 被使用一个并且允许超出范围.
In this code example, the ExecutorService is used one and allowed to go out of scope.
public static void main(String[] args)
{
ExecutorService executorService = Executors.newFixedThreadPool(3);
executorService.submit(new Runnable()
{
public void run()
{
System.out.println("hello");
}
});
}
一旦 executorService 超出范围,它应该被收集并最终确定.ThreadPoolExecutor 中的 finalize() 方法调用了 shutdown().
Once executorService is out of scope, it should get collected and finalized. The finalize() method in ThreadPoolExecutor calls shutdown().
/**
* Invokes {@code shutdown} when this executor is no longer
* referenced and it has no threads.
*/
protected void finalize() {
shutdown();
}
一旦调用了shutdown(),池线程应该终止并且JVM应该被允许退出.但是 executorSerivce 永远不会被收集,因此 JVM 仍然存在.甚至对 System.gc() 的调用似乎也不起作用.为什么即使在 main() 终止后 executorService 也没有被收集?
Once shutdown() is called, the pool threads should terminate and the JVM should be allowed to exit. However the executorSerivce is never getting collected and thus the JVM stays alive. Even calls to System.gc() don't seem to work. Why isn't executorService getting collected even after main() terminates?
注意:我知道我应该自己调用 shutdown(),而且我总是在测试之外进行.我很好奇为什么最终确定在这里不能作为备份.
Note: I know I should call shutdown() myself and I always do outside of testing. I'm curious why finalization isn't working as a back-up here.
推荐答案
这实际上与 GC 的非确定性没有任何关系,尽管它没有帮助!(这是您示例中的一个原因,但即使我们修复"它以消耗内存并强制收集,它仍然无法完成)
This doesn't really have anything to do with GC being non-deterministic, although it doesn't help! (That is one cause in your example, but even if we 'fixed' it to eat up memory and force a collection, it still wouldn't finalize)
执行器创建的工作线程是内部类,它们具有对执行器本身的引用.(他们需要它才能看到队列、运行状态等!)正在运行的线程不会被垃圾收集,因此池中的每个线程都具有该引用,它们将保持执行器处于活动状态,直到所有线程都死掉.如果您不手动执行某些操作来停止线程,它们将永远运行并且您的 JVM 将永远不会关闭.
The Worker threads that the executor creates are inner classes that have a reference back to the executor itself. (They need it to be able to see the queue, runstate, etc!) Running threads are not garbage collected, so with each Thread in the pool having that reference, they will keep the executor alive until all threads are dead. If you don't manually do something to stop the threads, they will keep running forever and your JVM will never shut down.
相关文章