假设我们有以下代码:
List<Future<?>> runningTasks;
ExecutorService executor;
...
void executeTask(Runnable task){
runningTasks.add(executor.submit(task));
}
我的问题是:
runningTasks
是否包含对task
对象的引用?- 它能保持多长时间?任务完成后它还持有吗?
- 为了避免内存泄漏,我是否必须小心删除添加到列表中的 future ?
最佳答案
直到执行者或 Future
对象持有对它的引用时是一个实现细节。因此,如果您的任务使用大量内存以至于您不得不担心内存使用,您应该在任务完成之前在任务中明确清理。
如果你看OpenJDK 1.6 source code在 ThreadPoolExecutor
中,您可以看到实际上底层 Future
对象实际上无限期地保留对底层可调用对象的引用(即只要存在对 的强引用code>Future
对象,可调用对象不能是 GCd)。 1.7 也是如此。从 1.8 开始,对它的引用被取消了。但是,您无法控制您的任务将在 ExecutorService
的哪个实现上运行。
使用 WeakReference
应该在实践中作为 Future
工作,因此一旦任务完成并且理智的实现,Callable
对象就可以被 GCd当任务完成时,ExecutorService
应该失去对它的引用。严格来说,这仍然取决于 ExecutorService 的实现。此外,使用 WeakReference 会增加惊人的开销。你最好直接明确地清理任何占用大量内存的对象。相反,如果您不分配大对象,那么我就不会担心。
当然,这个讨论与如果您不断向列表中添加 future 而不删除任何 future 会遇到的内存泄漏完全不同。如果您这样做,即使使用 WeakReference
也无济于事;你仍然会有内存泄漏。为此,只需遍历列表并删除已经完成因此没有用的 future 。每次都这样做真的很好,除非你有一个大得离谱的队列,因为这是非常快的。
关于java - executorService.submit(Runnable) 返回的 future 对象是否包含对可运行对象的任何引用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23014606/