我正在向Callable
a 提交对象ThreadPoolExecutor
,它们似乎一直存在于内存中。
使用 Eclipse 的 MAT 工具查看堆转储,可以看到Callable
对象被 aFutureTask$Sync
的可调用变量引用。这FutureTask$Sync
是由 aFutureTask
的同步变量引用的。这FutureTask
是由FutureTask$Sync
的this$0变量引用的。
我已经阅读了有关此内容(here、here和 on SO)的信息,似乎FutureTask
可调用对象包含在ThreadPoolExecutor
的 submit() 中永远持有对可调用对象的引用。
我感到困惑的是如何确保FutureTask
收集垃圾,以便它不会继续将可调用对象保存在内存中,并保存可调用对象可能保存在内存中的任何内容?
只是为了提供有关我的特定情况的更多详细信息,我正在尝试以ThreadPoolExecutor
一种允许在需要时取消所有提交的任务的方式来实现。我尝试了在 SO 和其他地方找到的几种不同方法,例如完全关闭执行程序(使用shutdown()
等shutdownNow()
)并保留期货返回列表submit()
并对所有它们调用取消,然后清除期货列表。理想情况下,我希望不必将其关闭,并cancel()
在需要时将其清除。
所有这些方法似乎都没有什么不同。如果我向池提交一个可调用的,它很有可能最终会留下来。
我究竟做错了什么?
谢谢。
编辑:
根据要求,这里是 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)
或者
getQueue.clear()
或循环保存对期货的引用并调用:
getQueue.remove(task)
任何这些情况都会导致 FutureTask 如上所述停留。
因此,所有这一切的真正问题是如何正确取消或从 ThreadPoolExecutor 中删除项目,以便 FutureTask 被垃圾收集并且不会永远泄漏?