java 为什么这个线程池没有被垃圾收集?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7728102/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 21:09:57  来源:igfitidea点击:

Why doesn't this thread pool get garbage collected?

javaconcurrencygarbage-collection

提问by Craig P. Motlin

In this code example, the ExecutorService is used one and allowed to go out of scope.

在此代码示例中,使用了 ExecutorService 并允许超出范围。

public static void main(String[] args)
{
    ExecutorService executorService = Executors.newFixedThreadPool(3);
    executorService.submit(new Runnable()
    {
        public void run()
        {
            System.out.println("hello");
        }
    });
}

Once executorService is out of scope, it should get collected and finalized. The finalize() method in ThreadPoolExecutor calls shutdown().

一旦 executorService 超出范围,它应该被收集并最终确定。ThreadPoolExecutor 中的 finalize() 方法调用了 shutdown()。

/**
 * Invokes {@code shutdown} when this executor is no longer
 * referenced and it has no threads.
 */
protected void finalize() {
    shutdown();
}

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(),池线程应该终止并且JVM应该被允许退出。然而 executorSerivce 永远不会被收集,因此 JVM 保持活动状态。甚至对 System.gc() 的调用似乎也不起作用。为什么即使在 main() 终止后也没有收集 executorService?

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.

注意:我知道我应该自己调用 shutdown() 并且我总是在测试之外进行。我很好奇为什么最终确定在这里不起作用。

回答by Affe

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)

这与 GC 的不确定性没有任何关系,尽管它没有帮助!(这是您的示例中的一个原因,但即使我们“修复”它以占用内存并强制收集,它仍然不会完成)

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.

执行器创建的工作线程是内部类,它们具有对执行器本身的引用。(他们需要它能够看到队列、运行状态等!)正在运行的线程不会被垃圾收集,因此池中的每个线程都具有该引用,它们将使执行程序保持活动状态,直到所有线程都死了。如果您不手动执行某些操作来停止线程,它们将永远运行并且您的 JVM 永远不会关闭。

回答by mjt

Affe is correct; the thread pool's threads will keep it from being garbage collected. When you call Executors.newFixedThreadPool(3) you get a ThreadPoolExecutor constructed like so:

Affe是正确的;线程池的线程会阻止它被垃圾收集。当您调用 Executors.newFixedThreadPool(3) 时,您会得到一个 ThreadPoolExecutor 构造如下:

ThreadPoolExecutor(3, 3, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());

And if you read the JavaDoc for ThreadPoolExecutor it says:

如果您阅读 ThreadPoolExecutor 的 JavaDoc,它会说:

A pool that is no longer referenced in a program AND has no remaining threads will be shutdown automatically. If you would like to ensure that unreferenced pools are reclaimed even if users forget to call shutdown(), then you must arrange that unused threads eventually die,by setting appropriate keep-alive times, using a lower bound of zero core threads and/or setting allowCoreThreadTimeOut(boolean).

程序中不再引用且没有剩余线程的池将自动关闭。如果您想确保即使用户忘记调用 shutdown() 也能回收未引用的池,那么您必须通过设置适当的保持活动时间、使用零核心线程的下限和/或设置 allowCoreThreadTimeOut(boolean)。

If you want your thread pool to finalize like you're expecting, you should do one of those things.

如果您希望您的线程池像您期望的那样最终确定,您应该做这些事情之一。

回答by jpse

Because garbage collection is “non deterministic” ie you cannot predict when it will happen, you thus cannot predict exactly when the finalize method will run. You can only make Objects eligible for GC and suggest gc with System.gc() without any guarantee.

因为垃圾收集是“非确定性的”,即您无法预测它何时发生,因此您无法准确预测 finalize 方法何时运行。您只能使对象符合 GC 条件,并在没有任何保证的情况下建议使用 System.gc() 进行 gc。

Even worse threads are OS specific handled by the JVM and are hardly predictable...

更糟糕的线程是由 JVM 处理的操作系统特定的,并且很难预测......

回答by nmikhailov

Finalizers are too unpredictable. Depending on them is usually bad practice. You can read more about it in "Effective java" by Joshua Bloch (item 1.7)

终结者太不可预测了。依赖它们通常是不好的做法。您可以在Joshua Bloch 的“Effective java”(第 1.7 项)中阅读更多相关信息

回答by gustafc

Once executorService is out of scope, it should get collected and finalized.

一旦 executorService 超出范围,它应该被收集并最终确定。

Not really - once it is out of scope, it couldget collected and finalized. There are no guarantees made in the VM specabout when objects are finalized, or even ifthey are finalized:

不是真的 - 一旦超出范围,它可能会被收集并最终确定。有没有在提供担保VM规格约当对象被最终确定,甚至如果他们被敲定:

The Java programming language does not specify how soon a finalizer will be invoked, except to say that it will happen before the storage for the object is reused.

Java 编程语言没有指定终结器将在多长时间内被调用,只是说它会在对象的存储被重用之前发生。