我正在提交Callable
对象到ThreadPoolExecutor
他们似乎一直留在记忆中。
使用 Eclipse 的 MAT 工具查看堆转储,可以看到Callable
对象正在被引用FutureTask$Sync
's callable多变的。那FutureTask$Sync
被引用为FutureTask
's sync多变的。那FutureTask
被引用的是FutureTask$Sync
's this$0多变的。
我读过有关此的内容(here, here,以及关于SO),看起来像FutureTask
可调用对象被包装在ThreadPoolExecutor
的submit() 永远保存对可调用对象的引用。
我感到困惑的是如何确保FutureTask
收集垃圾,以便它不会继续将可调用对象保留在内存中,并保留可调用对象可能在内存中保存的任何内容?
只是为了提供有关我的特殊情况的更多详细信息,我正在尝试实施ThreadPoolExecutor
允许在需要时取消所有已提交的任务。我尝试了在 SO 和其他地方找到的几种不同的方法,例如完全关闭执行器(使用shutdown()
, shutdownNow()
等)并保存期货收益清单submit()
并对所有这些调用取消,然后清除期货列表。理想情况下,我希望不必将其关闭,而只是cancel()
并在需要时清除。
所有这些方法似乎都没有什么作用。如果我向池中提交一个可调用对象,它很可能最终会保留下来。
我究竟做错了什么?
Thanks.
Edit:
根据要求,这里是 ThreadPoolExecutor 的构造函数。
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
}
经过进一步测试,我可以看到,如果我让已提交给 ThreadPoolExecutor 的任务完成,则不会出现泄漏。如果我尝试以任何方式取消它们,例如:
shutdownNow()
或者保存对未来的引用并稍后调用取消:
Future referenceToCancelLater = submit(task);
...
referenceToCancelLater.cancel(false);
或者通过使用以下方法将它们从队列中删除:
getQueue.drainTo(someList)
or
getQueue.clear()
或者
循环保存对 future 的引用并调用:
getQueue.remove(task)
任何一种情况都会导致 FutureTask 如上所述保留下来。
因此,所有这一切的真正问题是如何正确地从 ThreadPoolExecutor 中取消或删除项目,以便 FutureTask 被垃圾收集并且不会永远泄漏?