使用Java ExecutorService,我如何完成主动执行的任务,但停止等待任务的处理?

2022-09-03 13:47:05

我正在使用ExperidorService(ThreadPoolExecutor)来运行(和排队)很多任务。我正在尝试编写一些尽可能优雅的关闭代码。

ExecutorService 有两种关闭方式:

  1. 我可以打电话,然后.ExecutorService.shutdown()ExecutorService.awaitTermination(...)
  2. 我可以打电话给.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.

我想要在这两个选项之间找到一些东西。

我想调用一个命令:
a。完成当前活动的任务(如 )。
(二)停止处理等待的任务(如 )。shutdownshutdownNow

例如:假设我有一个线程池执行器,有3个线程。它当前在队列中有 50 个任务,前 3 个任务正在运行。我想允许这3个活动任务完成,但我不希望剩余的47个任务开始。

我相信我可以通过这种方式关闭执行器服务,方法是保留一个对象列表,然后调用所有对象。但是,由于任务是从多个线程提交到此执行器服务的,因此没有一种干净的方法来执行此操作。Futurecancel

我真的希望我错过了一些明显的东西,或者有一种方法可以干净利落地做到这一点。

感谢您的任何帮助。


答案 1

我最近遇到了这个问题。可能有一种更优雅的方法,但我的解决方案是首先调用,然后拉出正在使用的并调用它(或者将其排出到另一个进行存储)。最后,调用允许线程池完成其板上当前的内容。shutdown()BlockingQueueThreadPoolExecutorclear()CollectionawaitTermination()

例如:

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);
    }
}

此方法将在使用引用 包装的定向类中实现。ThreadPoolExecutorexecutor

请务必注意 ThreadPoolExecutor.getQueue() javadoc 中的以下内容:

对任务队列的访问主要用于调试和监视。此队列可能正在使用中。检索任务队列不会阻止排队任务的执行。

这突出了这样一个事实,即其他任务可能会在您耗尽任务时进行轮询。但是,根据该接口的文档,所有实现都是线程安全的,因此这不应该导致问题。BlockingQueueBlockingQueue


答案 2

这正是您所需要的。你错过了第一个单词尝试及其javadoc的整个第2段:shutdownNow()

除了尽最大努力停止处理主动执行的任务之外,没有其他保证。例如,典型的实现将取消 via ,因此任何无法响应中断的任务都可能永远不会终止。Thread.interrupt()

因此,只有定期检查 Thread#isInterrupted() 的任务(例如在循环中或其他内容)才会被终止。但是,如果您没有在任务中检查它,它仍然会继续运行。while (!Thread.currentThread().isInterrupted())