当前位置: 首页 > 面试题库 >

如何确保将FutureTask的垃圾回收提交给ThreadPoolExecutor然后取消?

谭高峯
2023-03-14
问题内容

我正在将Callable对象提交给,ThreadPoolExecutor并且它们似乎在内存中停留。

使用Eclipse的MAT工具查看堆转储,可以看到Callable对象FutureTask$Sync可调用
变量正在引用。这FutureTask$Sync是通过FutureTasksync
变量引用的。这FutureTask是由引用FutureTask$Sync这个$ 0 变量。

我已经阅读了有关此内容的内容,此处以及其他内容),并且似乎FutureTask可调用对象包装在ThreadPoolExecutor的commit()上,它永远包含对可调用对象的引用。

我感到困惑的是如何确保FutureTask收集的垃圾被收集起来,以使其不再继续在内存中保留可调用对象,而不在内存中保留任何可调用对象?

只是为了提供有关我的特定情况的更多详细信息,我正在尝试以ThreadPoolExecutor一种允许所有提交的任务在需要时被取消的方式实施。我已经尝试了在SO和其他地方发现的几种不同方法,例如完全关闭执行器(使用shutdown()shutdownNow()等),还保留期货收益列表,submit()并对其全部调用cancel,然后清除期货列表。理想情况下,我希望不必将其关闭,而是cancel()在需要时进行清理。

所有这些方法似乎都没有作用。如果我将可调用对象提交给池,则很有可能最终会卡住。

我究竟做错了什么?

谢谢。

编辑:

根据要求,这是ThreadPoolExecutor的构造函数。

public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
    super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
}

经过进一步的测试后,我可以看到,如果让已提交给ThreadPoolExecutor的任务完成,则不会泄漏。如果我尝试以任何方式取消它们,例如:

shutdownNow()

或保存对将来的引用并在以后调用cancel:

Future referenceToCancelLater = submit(task);
...
referenceToCancelLater.cancel(false);

或者使用以下方法将它们从队列中删除:

getQueue.drainTo(someList)

要么

getQueue.clear()

或循环浏览保存的期货参考并调用:

getQueue.remove(task)

这些情况中的任何一种都会导致FutureTask停留在上面所述的位置。

因此,所有这一切的真正问题是,如何正确地从ThreadPoolExecutor中取消或删除项目,以便FutureTask被垃圾收集且不会永远泄漏?


问题答案:

我什么都无法工作,所以我想出了以下解决方案。这是一个大概的概述:我在ThreadPoolExecutor中创建了一个数组,该数组跟踪队列中的可运行对象。然后,当我需要取消队列时,我遍历并在每个可运行对象上调用了cancel方法。就我而言,所有这些可运行对象都是我创建的自定义类,它们的cancel方法只是设置了canceled标志。当队列提出下一个要处理的队列时,在运行该可运行对象时,它将看到已取消并跳过了实际工作。

因此,所有可运行的对象都会被取消,很快就被一个接一个地快速清除。

可能不是最好的解决方案,但它对我有用,并且不会泄漏内存。



 类似资料:
  • 垃圾回收 我们对生产中花了很多时间来调整垃圾回收。垃圾回收的关注点与Java大致相似,尽管一些惯用的Scala代码比起惯用的Java代码会容易产生更多(短暂的)垃圾——函数式风格的副产品。Hotspot的分代垃圾收集通常使这不成问题,因为短暂的(short-lived)垃圾在大多情形下会被有效的释放掉。 在谈GC调优话题前,先看看这个Attila的报告,它阐述了我们在GC方面的一些经验。 Scal

  • 对于开发者来说,JavaScript 的内存管理是自动的、无形的。我们创建的原始值、对象、函数……这一切都会占用内存。 当我们不再需要某个东西时会发生什么?JavaScript 引擎如何发现它并清理它? 可达性(Reachability) JavaScript 中主要的内存管理概念是 可达性。 简而言之,“可达”值是那些以某种方式可访问或可用的值。它们一定是存储在内存中的。 这里列出固有的可达值的

  • 垃圾收集,引用计数,显式分配 和所有的现代语言一样,OCaml提供垃圾收集器,所以你不用像C/C++一样显式地分配和释放内存。 JWZ在他的文章 "Java sucks" rant(Java蛋疼(怒)!): 第一个好家伙是Java没有 free()。其他的都没有所谓了。这几乎掩盖了所有的缺点,不管有多糟糕, 这个有点让后续文档基本都没有意义了,但是...(译注:但是啥大家自己看吧) OCaml的垃

  • 主要内容:垃圾回收器函数,实例Lua 采用了自动内存管理。 这意味着你不用操心新创建的对象需要的内存如何分配出来, 也不用考虑在对象不再被使用后怎样释放它们所占用的内存。 Lua 运行了一个垃圾收集器来收集所有死对象 (即在 Lua 中不可能再访问到的对象)来完成自动内存管理的工作。 Lua 中所有用到的内存,如:字符串、表、用户数据、函数、线程、 内部结构等,都服从自动管理。 Lua 实现了一个增量标记-扫描收集器。 它使用

  • 主要内容:1 什么是Java 垃圾回收,2 Java 垃圾回收的优势,3 如何取消对象引用,4 finalize()方法,5 gc()方法,6 Java 垃圾回收的例子1 什么是Java 垃圾回收 在Java中,垃圾意味着未引用的对象。 垃圾回收是自动回收运行时未使用的内存的过程。换句话说,这是销毁未使用对象的一种方法。 我们在C语言中使用free() 函数,在C ++中使用delete()。但是,在Java中它是自动执行的。因此,java提供了更好的内存管理。 2 Java 垃圾回收的优势 它

  • 问题内容: 我想知道Java中发生的垃圾回收。它真的能够处理所有未使用的对象并释放最大可能的内存吗? 我还想知道Java垃圾收集与另一种语言(例如C#)相比如何?然后,如何自动垃圾收集与从像C这样的语言中进行手动收集相比又能达到更好的效果呢? 问题答案: 是的,这就是垃圾收集的重点。 有许多不同形式的垃圾收集。如果不增强算法,最简单的形式即引用计数就无法处理某些类型的垃圾(循环引用)。 Java(