CompletableFuture 在超时时未完成

CompletableFuture does not complete on timeout

我有一个从输入流读取的方法read。如果 read 超时后还没有完成,我想完成未来。

public static void main(String[] args) {
   CompletableFuture<?> future = new CompletableFuture<>();
   future
      .thenRunAsync(() -> {
         try {
            read(data);
         } catch (IOException e) {
            future.completeExceptionally(e);
         }
      })
      .orTimeout(1, TimeUnit.SECONDS);

   future.join();
} 

但是当我 运行 这段代码时,它并没有超时完成,而是等待输入流。

您的代码至少有两个问题:

  1. 未执行任何操作。 您创建一个 CompletableFuture,然后在其上调用 thenRunAsyncthenRunAsync 创建的阶段只会在 前一阶段 完成后触发。由于您从未完成原始 CompletableFuture 这永远不会发生。你也最终加入了一个永远不会完成的未来。

  2. 你加入错误的 CompletableFuture. 方法如 thenRunAsyncorTimeout return 一个 新实例 ,它创建了一种 "chain" 阶段。每个阶段都由其 "parent" 阶段的完成触发。为了完全理解这一点,我建议阅读 CompletionStage.

  3. 的文档

这是您的代码的示例,我怀疑您想要的方式:

public static void main(String[] args) {
  CompletableFuture.runAsync(
          () -> {
            try {
              read(data);
            } catch (IOException ex) {
              throw new UncheckedIOException(ex);
            }
          })
      .orTimeout(1L, TimeUnit.SECONDS)
      .join();
}

一些注意事项:

  • 使用 CompletableFuture#runAsync(Runnable) 创建了一个 "primordial" 舞台。当 Runnable 完成并且公共 ForkJoinPool 用于执行 Runnable.

  • 时,此阶段将完成
  • 如果抛出 runAsync 阶段中的 UncheckedIOException 将导致该阶段异常完成。

  • #join() 方法在实例 return 上被 orTimeout(1L, TimeUnit.SECONDS) 调用调用。现在,如果超时结束,对 join() 的调用将抛出 CompletionException 包装 TimeoutException.

警告:调用read没有被打断1超时后会继续执行在后台。这是因为 CompletableFuture 没有引用正在执行的线程,因此无法中断它们。


1.假设中断会 .