删除 ThreadPoolExecutor 的所有排队任务
Posted
技术标签:
【中文标题】删除 ThreadPoolExecutor 的所有排队任务【英文标题】:Removing all queued tasks of an ThreadPoolExecutor 【发布时间】:2010-12-13 08:51:01 【问题描述】:我对@987654321@ 有一个相当简单的问题。我有以下情况:我必须使用队列中的对象,为它们创建适当的工作任务并将它们提交给 ThreadPoolExecutor。这很简单。但在关闭场景中,许多工作人员可能会排队等待执行。由于其中一个任务可能会运行一个小时,并且我希望相对快速地正常关闭应用程序,因此我想丢弃 ThreadPoolExecutor 中的所有排队任务,而已经处理的任务应该正常完成。
ThreadPoolExecutor 文档有一个remove() 方法,但只允许删除特定任务。 purge() 仅适用于已取消的未来任务。我的想法是清除包含所有排队任务的队列。 ThreadPoolExecutor 提供对此内部队列的访问,但文档指出:
方法 getQueue() 允许访问 用于监控目的的工作队列 和调试。这种方法的使用 出于任何其他目的强烈 气馁。
因此,抓住这个队列并清除它不是一种选择。此外,这个文档的 sn-p 说:
两种提供的方法, 删除(java.lang.Runnable)和清除() 可用于协助存储 大量回收时 排队的任务被取消。
怎么样?当然,我可以维护我提交给执行程序的所有任务的列表,并且在关闭的情况下,我遍历所有条目并使用 remove() 方法将它们从 ThreadPoolExecutor 中删除......但是......来吧,这是一个浪费内存并且维护这个列表很麻烦。 (例如删除已经执行的任务)
感谢任何提示或解决方案!
【问题讨论】:
【参考方案1】:由于ExecutorService.shutdown() 做得不够,而ExecutorService.shutdownNow() 做得太多,我猜你必须在中间写一些东西:记住所有提交的任务,并在调用shutdown()
之后(或之前)手动删除它们。
【讨论】:
"启动有序关闭,执行之前提交的任务,但不会接受新任务。"我提交了几个不应再执行的任务。但是正在执行的任务不应该结束。 您编辑了答案,因此我的评论不再完全有效。然而,shutdownNow() 文档指出:“尝试停止所有正在执行的任务。”这不是我想要的。 :) 哦,对了,我看了一半的句子。好吧,我想你唯一的选择是记住所有提交的Runnable
s 并手动删除它们。我会相应地进行编辑。【参考方案2】:
Bombe 的答案正是您想要的。 shutdownNow()
使用 nuke and pave 方法停止一切。这是您能做的最好的事情,没有子类化您正在使用的 ThreadPoolExecutor
的实现。
【讨论】:
【参考方案3】:一个可能有效的疯狂和不干净的解决方案(没有经过深思熟虑或测试)将覆盖您的 WorkerTasks 的 interrupt()
,只有在设置了某些全局值的情况下才会在调用 interrupt()
时拒绝关闭它们通过 shutdownNow()。
那应该允许您使用shutdownNow()
否?
【讨论】:
【参考方案4】:告诉你的线程池关闭,getQueue,将每个结果放入单独的 Runnables,使用 remove 方法删除每个 Runnable。根据队列的类型,您可能能够根据返回值提前停止删除。
基本上,这是抓取队列并清除它,仅通过有效的方法进行清除。您无需手动记住所有提交,而是使用线程池已经必须记住所有提交的事实。但是,您可能需要制作队列的防御性副本,因为我认为它是实时视图,因此如果您在实时视图上迭代/for-eaching,则删除可能会导致并发修改异常。
【讨论】:
【参考方案5】:我曾经在一个具有长时间运行线程的应用程序上工作。我们在关机时执行此操作,
BlockingQueue<Runnable> queue = threadPool.getQueue();
List<Runnable> list = new ArrayList<Runnable>();
int tasks = queue.drainTo(list);
列表被保存到一个文件中。启动时,列表会重新添加到池中,因此我们不会丢失任何工作。
【讨论】:
很好地补充了我的问题。 :-) 我的情况下,任务的持久性不是问题。但是您的添加可能会对其他人有所帮助,谢谢! :) 我不确定这是正确的方法。如果您通过shutdown() 关闭,它会一直等到所有内容都终止(甚至是排队的任务),如果您使用shutdownNow() 执行此操作,则该方法已经返回给您排空的排队任务列表。仅供参考。【参考方案6】:您是否考虑过包装 ExecutorService?创建一个
CleanShutdownExecutorService implements Executor
将所有调用委托给另一个 Executor,但将 Futures 保存在自己的列表中。然后 CleanShutdownExecutorService 可以有一个 cancelRemainingTasks() 方法,该方法调用 shutdown(),然后在其列表中的所有 Futures 上调用 cancel(false)。
【讨论】:
这可能是最干净的方法,因此我接受这个答案。 :-) 即使我希望已经有类似的东西......所以:让我们编写这个东西。 :-)【参考方案7】:awaitTermination(long timeout, TimeUnit unit)
关机后不工作吗?
executor.shutdown(); executor.awaitTermination(60, TimeUnit.SECONDS)
【讨论】:
【参考方案8】:你可以试试allowCoreThreadTimeOut(true);
【讨论】:
您应该制定自己的答案并明确表明您实际上是在回答 OP。【参考方案9】:这是一个老问题,但如果这对其他人有帮助:您可以在调用 shutdown() 时设置一个 volatile 布尔值,如果在真正开始之前设置了该布尔值,则每个提交的任务都会终止。这将允许真正开始完成的任务,但会阻止排队的任务开始其实际活动。
【讨论】:
【参考方案10】:您可以创建自己的任务队列并将其传递给ThreadPoolExecutor
构造函数:
int poolSize = 1; // number of threads
BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>();
Executor executor = new ThreadPoolExecutor(poolSize, poolSize, 0L, TimeUnit.MILLISECONDS, queue);
当您清除代码中某处的队列时,其余任务将不会执行:
queue.clear();
【讨论】:
以上是关于删除 ThreadPoolExecutor 的所有排队任务的主要内容,如果未能解决你的问题,请参考以下文章
如何在不关闭 Executor 的情况下等待 ThreadPoolExecutor 中的所有任务完成?