删除ThreadPoolExecutor的所有排队任务

我有关于ThreadPoolExecutor的这个相当简单的问题。 我有以下情况:我必须从队列中使用对象,为它们创建适当的工作任务并将它们提交给ThreadPoolExecutor。 这很简单。 但在关闭情况下, 许多工作人员可能会排队等待执行。 由于其中一个任务可能运行了一个小时,并且我想要相对快速地正常关闭应用程序,我想从ThreadPoolExecutor中丢弃所有排队的任务,而已经处理的任务应该正常完成。

ThreadPoolExecutor文档有一个remove()方法,但只允许删除特定的任务。 purge()仅适用于已取消的Future任务。 我的想法是清除队列中包含所有排队的任务。 ThreadPoolExecutor提供对此内部队列的访问,但文档指出:

方法getQueue()允许访问工作队列以进行监视和调试。 强烈建议不要将此方法用于任何其他目的。

所以抓住这个队列并清除它不是一个选择。 此外,该文档的片段说:

当大量排队的任务被取消时,两个提供的方法remove(java.lang.Runnable)和purge()可用于协助存储回收。

怎么样? 当然,我可以维护我提交给执行程序的所有任务的列表,在关闭的情况下,我遍历所有条目并使用remove()方法从ThreadPoolExecutor中删除它们……但是…来吧,这是一个浪费记忆力和维护这份清单的麻烦。 (例如删除已执行的任务)

我感谢任何提示或解决方案!

你考虑过包装ExecutorService吗? 创建一个

CleanShutdownExecutorService implements Executor 

将所有调用委托给另一个Executor,但将Futures保留在自己的列表中。 然后,CleanShutdownExecutorService可以使用cancelRemainingTasks()方法调用shutdown(),然后在其列表中的所有Futures上调用cancel(false)。

我曾经在使用长线程的应用程序上工作。 我们在关机时这样做

 BlockingQueue queue = threadPool.getQueue(); List list = new ArrayList(); int tasks = queue.drainTo(list); 

该列表将保存到文件中。 在启动时,列表将添加回池中,因此我们不会丢失任何作业。

由于ExecutorService.shutdown()做得不够而且ExecutorService.shutdownNow()做得太多,我猜你必须在中间写一些东西:记住所有提交的任务并在调用shutdown()之后(或之前)手动删除它们。

这是一个老问题,但是如果这有助于其他人:你可以在调用shutdown()时设置一个volatile布尔值,并且如果在真正启动之前设置了该布尔值,则每个提交的任务都会终止。 这将允许真正开始完成的任务,但会阻止排队的任务开始其实际活动。

Bombe的答案正是你想要的。 shutdownNow()使用nuke和pave方法停止一切。 这是你能做的最好的事情,除了你正在使用的ThreadPoolExecutor的实现的子类化。

你可以尝试allowCoreThreadTimeOut(true);

一个疯狂且不干净的解决方案可能会工作(不是真正的思考或测试)将覆盖您的WorkerTasks的interrupt() ,只有在设置某些全局值时,如果在shutdownNow上调用interrupt()时拒绝关闭它( )。

那应该允许你使用shutdownNow()没有?

告诉你的线程池关闭,getQueue,for-each结果到单个Runnables,使用remove方法删除每个Runnable。 根据队列的类型,您可以根据返回值提前暂停删除。

基本上,这是抓住队列并清除它,只通过有效的方法清除。 您可以使用线程池已经记住所有提交的事实,而不是手动记住所有提交。 但是,您可能需要制作队列的防御副本,因为我认为它是实时视图,因此如果您在实时视图上进行迭代/遍历,则删除可能会导致并发修改exception。

关机后awaitTermination(long timeout, TimeUnit unit)工作吗?

executor.shutdown(); executor.awaitTermination(60,TimeUnit.SECONDS)

您可以创建自己的任务队列并将其传递给ThreadPoolExecutor构造函数:

 int poolSize = 1; // number of threads BlockingQueue queue = new ArrayBlockingQueue<>(); Executor executor = new ThreadPoolExecutor(poolSize, poolSize, 0L, TimeUnit.MILLISECONDS, queue); 

当您在代码中的某处清除队列时,其余任务将不会执行:

 queue.clear();