CompletableFuture.allOf().orTimeout() 的意外行为

Chr*_*ris 5 java asynchronous timeout future

有两种方法可以强制 aCompletableFuture在给定时间后超时:

我希望他们也有同样的行为。然而,当应用于 时CompletableFuture.allOf(CompletableFuture<?>... cfs),这两种提供超时的方式表现得非常不同!

基本上,它似乎get()符合我的预期(它阻塞当前线程,直到所有 future 完成),而orTimeout()似乎行为非常奇怪(它在第一个 future 完成后尽快解锁当前线程)。

这是一些代码来演示我观察到的行为:

import org.junit.Test;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;

import static java.util.concurrent.TimeUnit.MILLISECONDS;

public class AllOfWithTimeoutTest {

    public static final int TIMEOUT_IN_MILLIS = 100;

    @Test
    public void allOfOrTimeout1() throws InterruptedException, ExecutionException, TimeoutException {
        getAllOfFuture().get(TIMEOUT_IN_MILLIS, MILLISECONDS);
    }

    @Test
    public void allOfOrTimeout2() throws ExecutionException, InterruptedException {
        getAllOfFuture().orTimeout(TIMEOUT_IN_MILLIS, MILLISECONDS);
    }

    private CompletableFuture<Void> getAllOfFuture() {
        return CompletableFuture.allOf(
            CompletableFuture.runAsync(() -> sleep(1)),
            CompletableFuture.runAsync(() -> sleep(2)),
            CompletableFuture.runAsync(() -> sleep(3)),
            CompletableFuture.runAsync(() -> sleep(4)),
            CompletableFuture.runAsync(() -> sleep(5)),
            CompletableFuture.runAsync(() -> sleep(6)),
            CompletableFuture.runAsync(() -> sleep(7)),
            CompletableFuture.runAsync(() -> sleep(8))
        );
    }

    public static void sleep(int millis) {
        try {
            Thread.sleep(millis);
            System.out.format("Had a nap for %s milliseconds.\r\n", millis);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    };
}
Run Code Online (Sandbox Code Playgroud)

打印输出allOfOrTimeout1()是我所期望的:

Had a nap for 1 milliseconds.
Had a nap for 2 milliseconds.
Had a nap for 3 milliseconds.
Had a nap for 4 milliseconds.
Had a nap for 5 milliseconds.
Had a nap for 6 milliseconds.
Had a nap for 7 milliseconds.
Had a nap for 8 milliseconds.
Run Code Online (Sandbox Code Playgroud)

的打印输出allOfOrTimeout2()不是我所期望的,并且每次执行时都会略有不同。它通常会打印前 2 行到第 5 行,但绝不会打印第 8 行。这是一个仅打印 2 行的版本:

Had a nap for 1 milliseconds.
Had a nap for 2 milliseconds.
Run Code Online (Sandbox Code Playgroud)

另外,如果我在 IntelliJ 中运行整个测试,我会在最后得到一些额外的行:

Had a nap for 1 milliseconds.
Had a nap for 2 milliseconds.
Had a nap for 3 milliseconds.
Had a nap for 4 milliseconds.
Had a nap for 5 milliseconds.
Had a nap for 6 milliseconds.
Had a nap for 7 milliseconds.
Had a nap for 8 milliseconds.



Had a nap for 1 milliseconds.
Had a nap for 2 milliseconds.

Had a nap for 3 milliseconds.
Had a nap for 4 milliseconds.

Process finished with exit code 0
Had a nap for 
Run Code Online (Sandbox Code Playgroud)

我的问题是:

  1. 这是 的预期行为吗orTimeout()
  2. 如果不是,为什么要这样做?

use*_*814 0

这是 orTimeout() 的预期行为吗?

是的。

OrTimeout是非阻塞异步调用,而get是阻塞异步调用。