如何在完成当前执行的任务后关闭 CompletionService

How to shutdown CompletionService after completing currently executed tasks

我有这样的东西:

ExecutorService executor = Executors.newFixedThreadPool(2);
CompletionService<Boolean> completionService = new ExecutorCompletionService<>(executor);
int i = 0;
while (i < 40) {
  completionService.submit(getTask());
  i++;
}
executor.shutdown();
System.out.println("SHUTDOWN");

调用shutdown后,所有提交的任务都会执行。如果我调用 shutdownNow,则当前执行的线程将抛出 java.lang.InterruptedException.

有什么方法可以等待当前执行的任务完成而不执行其他提交的任务吗?

是的,在您调用shutdown()之后,执行器将不再接受任何新任务。接下来您调用 awaitTermination() 等待 运行 任务完成。

shutdown() 允许完成当前提交的任务,但拒绝新任务:

Initiates an orderly shutdown in which previously submitted tasks are executed, but no new tasks will be accepted.

如果您想在 main 线程中等待执行程序关闭,您可以调用 executor.awaitTermination(long timeout, TimeUnit unit):

Blocks until all tasks have completed execution after a shutdown request, or the timeout occurs, or the current thread is interrupted, whichever happens first.

如果你想让当前运行的任务完成,但丢弃已经提交到队列的任务,你有几个选择:

  • 取消期货 cancel(false):

    Attempts to cancel execution of this task. This attempt will fail if the task has already completed, has already been cancelled, or could not be cancelled for some other reason. If successful, and this task has not started when cancel is called, this task should never run.

    Returns: false if the task could not be cancelled, typically because it has already completed normally; true otherwise

  • 用自定义 CancellableRunnable/Callable 包装你的 Runnable/Callable(取决于你的 getTask() returns):

    class CancellableRunnable implements Runnable {
    
        private final AtomicBoolean shouldRun;
        private final Runnable delegate;
    
        public CancellableRunnable(AtomicBoolean shouldRun, Runnable delegate) {
            this.shouldRun = shouldRun;
            this.delegate = delegate;
        }
    
        @Override
        public void run() {
            if (shouldRun.get()) {
                delegate.run();
            }
        }
    }
    

    以及您示例中的用法:

    AtomicBoolean shouldRun = new AtomicBoolean(true);
    while (i < 40) {
      completionService.submit(new CancellableRunnable(shouldRun, getTask()));
      i++;
    }
    shouldRun.set(false);
    executor.shutdown();
    

如果你只想要前两个结果然后放弃其他任务,你可以等待前两个任务完成然后取消其他任务,例如如果你不需要完成则调用shutdownNow不再服务。

Future<Boolean> result1 = copmletionService.take();
Future<Boolean> result2 = copmletionService.take();
completionService.shutdownNow();