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退出。但是,执行器服务永远不会被收集,因此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(),而且我总是在测试之外做。我很好奇为什么最终确定不作为备份在这里工作。
5 个解决方案
#1
47
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.
执行程序创建的Worker线程是内部类,它们具有对执行程序本身的引用。 (他们需要它能够看到队列,运行状态等等!)运行线程不是垃圾收集的,所以当池中的每个线程都有该引用时,它们将使执行器保持活动状态直到所有线程都死亡。如果您不手动执行某些操作来停止线程,它们将永远运行,您的JVM将永远不会关闭。
#2
18
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:
情感是正确的;线程池的线程将防止它被垃圾收集。当您调用Executors.newFixedThreadPool(3)时,您将获得如此构造的ThreadPoolExecutor:
ThreadPoolExecutor(3, 3, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
And if you read the JavaDoc for ThreadPoolExecutor it says:
如果您阅读了ThreadDoolExecutor的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.
如果你想让你的线程池像你期望的那样完成,你应该做其中的一件事。
#3
0
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.
因为垃圾收集是“非确定性的”,即您无法预测它何时会发生,因此您无法准确预测最终化方法何时运行。您只能使对象符合GC条件,并且无需任何保证即可向System.gc()建议gc。
Even worse threads are OS specific handled by the JVM and are hardly predictable...
更糟糕的线程是由JVM处理的操作系统特定的,并且难以预测......
#4
0
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项)
#5
0
Once executorService is out of scope, it should get collected and finalized.
一旦executorService超出范围,就应该收集并最终确定。
Not really - once it is out of scope, it could get collected and finalized. There are no guarantees made in the VM spec about when objects are finalized, or even if they 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编程语言没有指定调用终结器的时间,除非说它将在重用对象的存储之前发生。
#1
47
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.
执行程序创建的Worker线程是内部类,它们具有对执行程序本身的引用。 (他们需要它能够看到队列,运行状态等等!)运行线程不是垃圾收集的,所以当池中的每个线程都有该引用时,它们将使执行器保持活动状态直到所有线程都死亡。如果您不手动执行某些操作来停止线程,它们将永远运行,您的JVM将永远不会关闭。
#2
18
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:
情感是正确的;线程池的线程将防止它被垃圾收集。当您调用Executors.newFixedThreadPool(3)时,您将获得如此构造的ThreadPoolExecutor:
ThreadPoolExecutor(3, 3, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
And if you read the JavaDoc for ThreadPoolExecutor it says:
如果您阅读了ThreadDoolExecutor的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.
如果你想让你的线程池像你期望的那样完成,你应该做其中的一件事。
#3
0
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.
因为垃圾收集是“非确定性的”,即您无法预测它何时会发生,因此您无法准确预测最终化方法何时运行。您只能使对象符合GC条件,并且无需任何保证即可向System.gc()建议gc。
Even worse threads are OS specific handled by the JVM and are hardly predictable...
更糟糕的线程是由JVM处理的操作系统特定的,并且难以预测......
#4
0
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项)
#5
0
Once executorService is out of scope, it should get collected and finalized.
一旦executorService超出范围,就应该收集并最终确定。
Not really - once it is out of scope, it could get collected and finalized. There are no guarantees made in the VM spec about when objects are finalized, or even if they 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编程语言没有指定调用终结器的时间,除非说它将在重用对象的存储之前发生。