我使用ExecutorService(ThreadPoolExecutor)来运行(和排队)很多任务。我试图编写一些尽可能优雅的关闭代码。
ExecutorService有两种关闭方式:
ExecutorService.shutdown()
然后ExecutorService.awaitTermination(...)
。ExecutorService.shutdownNow()
。根据JavaDoc,shutdown
命令:
Initiates an orderly shutdown in which previously submitted
tasks are executed, but no new tasks will be accepted.
shutdownNow
命令:
Attempts to stop all actively executing tasks, halts the
processing of waiting tasks, and returns a list of the tasks that were
awaiting execution.
我想在这两个选项之间找到一些东西。
我想叫一个命令:
一个。完成当前活动的任务(如shutdown
)
湾暂停等待任务的处理(如shutdownNow
)。
例如:假设我有一个包含3个线程的ThreadPoolExecutor。它目前在队列中有50个任务,前3个正在运行。我希望允许完成这3个活动任务,但我不希望剩下的47个任务开始。
我相信我可以通过保留Future
对象列表然后在所有对象上调用cancel
来以这种方式关闭ExecutorService。但是,由于任务是从多个线程提交给此ExecutorService的,因此没有一种干净的方法可以执行此操作。
我真的希望我错过一些明显的东西,或者有办法干净利落地做。
感谢您的帮助。
答案 0 :(得分:10)
我最近遇到过这个问题。可能有更优雅的方法,但我的解决方案是首先致电shutdown()
,然后取出BlockingQueue
使用的ThreadPoolExecutor
并在其上调用clear()
(或否则将其排放到另一个Collection
进行存储。最后,调用awaitTermination()
允许线程池完成当前的工作。
例如:
public static void shutdownPool(boolean awaitTermination) throws InterruptedException {
//call shutdown to prevent new tasks from being submitted
executor.shutdown();
//get a reference to the Queue
final BlockingQueue<Runnable> blockingQueue = executor.getQueue();
//clear the Queue
blockingQueue.clear();
//or else copy its contents here with a while loop and remove()
//wait for active tasks to be completed
if (awaitTermination) {
executor.awaitTermination(SHUTDOWN_TIMEOUT, TimeUnit.SECONDS);
}
}
此方法将在引导类中使用引用ThreadPoolExecutor
包裹executor
来实现。
请注意ThreadPoolExecutor.getQueue()
javadoc中的以下内容:
访问任务队列主要用于调试和 监控。此队列可能正在使用中。检索任务队列 不会阻止排队的任务执行。
这突出了这样一个事实,即在您排除其他任务时,可能会从BlockingQueue
轮询其他任务。但是,根据that interface's documentation,所有BlockingQueue
实现都是线程安全的,因此这不会导致问题。
答案 1 :(得分:5)
您可以使用一些额外的逻辑来包装每个提交的任务
wrapper = new Runnable()
public void run()
if(executorService.isShutdown())
throw new Error("shutdown");
task.run();
executorService.submit(wrapper);
额外检查的开销可以忽略不计。关闭执行程序后,仍会执行包装器,但原始任务不会执行。
答案 2 :(得分:4)
shutdownNow()
正是您所需要的。您错过了第一个单词 Attempts 以及javadoc的整个第二段:
除了尽力尝试停止处理主动执行任务之外,没有任何保证。例如,典型的实现将通过
Thread.interrupt()
取消,因此任何未能响应中断的任务都可能永远不会终止。
因此,只有定期检查Thread#isInterrupted()
的任务(例如在while (!Thread.currentThread().isInterrupted())
循环或其他内容中)才会被终止。但如果您没有在任务中检查它,它仍将继续运行。