jdk8 之后 Future、CompletableFuture 的新增方法

jdk8 之后 Future、CompletableFuture 的新增方法

Future jdk19

任务状态

java 复制代码
/**
 * Represents the computation state.
 * @since 19
 */
enum State {
    /**
     * 未完成
     */
    RUNNING,
    /**
     * 正常结束,可获取结果
     */
    SUCCESS,
    /**
     * 异常结束,获取结果会抛出异常
     */
    FAILED,
    /**
     * 被取消了,获取结果会抛出异常 CancellationException
     */
    CANCELLED
}
java 复制代码
default State state()

四个任务状态,以及一个获取状态的方法

测试 RUNNING、SUCCESS

java 复制代码
static void test1() throws ExecutionException, InterruptedException {
    ExecutorService executor = Executors.newSingleThreadExecutor();
    Future<String> future = executor.submit(() -> {
        TimeUnit.SECONDS.sleep(1);
        return "ok";
    });
    IO.println(future.state());

    String result = future.get();
    IO.println(result);
    IO.println(future.state());
}
复制代码
RUNNING
ok
FAILED

测试 FAILED

java 复制代码
static void test2() throws ExecutionException, InterruptedException {
    ExecutorService executor = Executors.newSingleThreadExecutor();
    Future<String> future = executor.submit(() -> {
        TimeUnit.SECONDS.sleep(1);
        throw new RuntimeException();
    });
    IO.println(future.state());

    TimeUnit.SECONDS.sleep(2);
    IO.println(future.state());
    future.get();
}
复制代码
RUNNING
FAILED
Exception in thread "main" java.util.concurrent.ExecutionException: java.lang.RuntimeException
	at java.base/java.util.concurrent.FutureTask.report(FutureTask.java:124)
	at java.base/java.util.concurrent.FutureTask.get(FutureTask.java:193)
	at com.zbs.jdk.FutureTest1.test2(FutureTest1.java:42)
	at com.zbs.jdk.FutureTest1.main(FutureTest1.java:15)
Caused by: java.lang.RuntimeException
	at com.zbs.jdk.FutureTest1.lambda$test2$0(FutureTest1.java:36)
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:328)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1090)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:614)
	at java.base/java.lang.Thread.run(Thread.java:1474)

测试 CANCELLED

java 复制代码
static void test3() throws ExecutionException, InterruptedException {
    ExecutorService executor = Executors.newSingleThreadExecutor();
    Future<String> future = executor.submit(() -> {
        TimeUnit.SECONDS.sleep(1);
        return "ok";
    });
    IO.println(future.state());
    future.cancel(true);

    IO.println(future.state());

    String result = future.get();
    IO.println(result);
}
复制代码
RUNNING
CANCELLED
Exception in thread "main" java.util.concurrent.CancellationException
	at java.base/java.util.concurrent.FutureTask.report(FutureTask.java:123)
	at java.base/java.util.concurrent.FutureTask.get(FutureTask.java:193)
	at com.zbs.jdk.FutureTest1.test3(FutureTest1.java:56)
	at com.zbs.jdk.FutureTest1.main(FutureTest1.java:16)

resultNow

java 复制代码
default V resultNow()

返回任务正常完成时的结果,不会阻塞等待,若任务状态不是 SUCCESS 会抛出异常。该方法适用于调用者已知任务已成功完成的情况。

测试 SUCCESS

java 复制代码
static void test1() {
    ExecutorService executor = Executors.newCachedThreadPool();
    List<Future<?>> futures = new ArrayList<>(3);

    futures.add(executor.submit(() -> "task1 ok"));
    futures.add(executor.submit(() -> {
        throw new RuntimeException();
    }));
    futures.add(executor.submit(() -> "task3 ok"));

    List<?> results = futures.stream()
            .filter(f -> f.state() == Future.State.SUCCESS)
            .map(Future::resultNow)
            .toList();
    IO.println(results);
}
复制代码
[task1 ok, task3 ok]

如果任务未正常完成,会抛异常。

测试 RUNNING

java 复制代码
static void test2() throws InterruptedException {
    ExecutorService executor = Executors.newCachedThreadPool();
    Future<?> future = executor.submit(() -> {
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException _) {
            Thread.currentThread().interrupt();
        }
    });

    TimeUnit.SECONDS.sleep(1);
    IO.println(future.resultNow());
}
复制代码
Exception in thread "main" java.lang.IllegalStateException: Task has not completed
	at java.base/java.util.concurrent.FutureTask.resultNow(FutureTask.java:225)
	at com.zbs.jdk.FutureTest2.test2(FutureTest2.java:47)
	at com.zbs.jdk.FutureTest2.main(FutureTest2.java:16)

测试 FAILED

java 复制代码
static void test3() throws InterruptedException {
    ExecutorService executor = Executors.newCachedThreadPool();
    Future<?> future = executor.submit(() -> {
        throw new RuntimeException();
    });

    TimeUnit.SECONDS.sleep(1);
    IO.println(future.resultNow());
}
复制代码
Exception in thread "main" java.lang.IllegalStateException: Task completed with exception
	at java.base/java.util.concurrent.FutureTask.resultNow(FutureTask.java:221)
	at com.zbs.jdk.FutureTest2.test3(FutureTest2.java:58)
	at com.zbs.jdk.FutureTest2.main(FutureTest2.java:17)

测试 CANCELLED

java 复制代码
static void test4() {
    ExecutorService executor = Executors.newCachedThreadPool();
    Future<?> future = executor.submit(() -> {
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException _) {
            Thread.currentThread().interrupt();
        }
    });

    future.cancel(true);
    IO.println(future.resultNow());
}
复制代码
Exception in thread "main" java.lang.IllegalStateException: Task was cancelled
	at java.base/java.util.concurrent.FutureTask.resultNow(FutureTask.java:223)
	at com.zbs.jdk.FutureTest2.test4(FutureTest2.java:73)
	at com.zbs.jdk.FutureTest2.main(FutureTest2.java:18)

exceptionNow

java 复制代码
default Throwable exceptionNow()

resultNow() 相反,返回任务异常完成时抛出的异常,不会阻塞等待,若任务状态不是 FAILED 会抛出异常。适用于调用者知道任务已经完成但抛出异常的情况(不包含任务被取消的情况)。

测试 FAILED

java 复制代码
static void test1() {
    ExecutorService executor = Executors.newCachedThreadPool();
    List<Future<?>> futures = new ArrayList<>(3);

    futures.add(executor.submit(() -> "task1 ok"));
    futures.add(executor.submit(() -> {
        throw new RuntimeException("task 2 ex");
    }));
    futures.add(executor.submit(() -> "task3 ok"));

    List<?> results = futures.stream()
            .filter(f -> f.state() == Future.State.FAILED)
            .map(Future::exceptionNow)
            .toList();
    IO.println(results);
}
复制代码
[java.lang.RuntimeException: task 2 ex]
java 复制代码
static void test3() throws InterruptedException {
    ExecutorService executor = Executors.newCachedThreadPool();
    Future<?> future = executor.submit(() -> {
        throw new RuntimeException();
    });

    TimeUnit.SECONDS.sleep(1);
    IO.println(future.state());
    IO.println(future.exceptionNow());
}
复制代码
FAILED
java.lang.RuntimeException

调用方法时,如果任务未以抛出异常的方式完成,则会抛出异常。

测试 RUNNING

java 复制代码
static void test2() throws InterruptedException {
    ExecutorService executor = Executors.newCachedThreadPool();
    Future<?> future = executor.submit(() -> {
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException _) {
            Thread.currentThread().interrupt();
        }
    });

    TimeUnit.SECONDS.sleep(1);
    IO.println(future.state());
    IO.println(future.exceptionNow());
}
复制代码
RUNNING
Exception in thread "main" java.lang.IllegalStateException: Task has not completed
	at java.base/java.util.concurrent.FutureTask.exceptionNow(FutureTask.java:243)
	at com.zbs.jdk.FutureTest3.test2(FutureTest3.java:52)
	at com.zbs.jdk.FutureTest3.main(FutureTest3.java:17)

测试 SUCCESS

java 复制代码
static void test4() throws InterruptedException {
    ExecutorService executor = Executors.newSingleThreadExecutor();
    Future<String> future = executor.submit(() -> "ok");

    TimeUnit.SECONDS.sleep(1);
    IO.println(future.state());
    IO.println(future.exceptionNow());
}
复制代码
SUCCESS
Exception in thread "main" java.lang.IllegalStateException: Task completed with a result
	at java.base/java.util.concurrent.FutureTask.exceptionNow(FutureTask.java:236)
	at com.zbs.jdk.FutureTest3.test4(FutureTest3.java:72)
	at com.zbs.jdk.FutureTest3.main(FutureTest3.java:19)

测试 CANCELLED

java 复制代码
static void test5() {
    ExecutorService executor = Executors.newCachedThreadPool();
    Future<?> future = executor.submit(() -> {
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException _) {
            Thread.currentThread().interrupt();
        }
    });

    future.cancel(true);
    IO.println(future.state());
    IO.println(future.exceptionNow());
}
复制代码
CANCELLED
Exception in thread "main" java.lang.IllegalStateException: Task was cancelled
	at java.base/java.util.concurrent.FutureTask.exceptionNow(FutureTask.java:241)
	at com.zbs.jdk.FutureTest3.test5(FutureTest3.java:88)
	at com.zbs.jdk.FutureTest3.main(FutureTest3.java:20)

CompletableFuture jdk9

CompletableFuture 实现了 Future 接口,所以也具备上述的功能。

关于调用线程的情况如下:

  1. 大多数不以 Async 结尾的方法(比如 thenRun、thenApply、exceptionally、exceptionallyCompose)的执行线程:如果执行本方法时前一个阶段已经执行结束,则会在调用本方法线程中阻塞的执行本方法的逻辑,如果前一个阶段没有执行结束,则会在执行前一个阶段的线程中执行本方法的逻辑。

  2. xxAsync(...) 方法的执行线程是默认线程池,也就是 ForkJoinPool.asyncCommonPool()

  3. xxAsync(..., Executor executor) 方法的执行线程是线程池 executor

以下不再赘述。

defaultExecutor

java 复制代码
public Executor defaultExecutor() {
    return ASYNC_POOL;
}

返回 async 方法不指定 Executor 时的默认 Executor。默认实现返回 ForkJoinPool.asyncCommonPool()

java 复制代码
static void main() {
    IO.println(CompletableFuture.completedFuture(1).defaultExecutor());
}
复制代码
java.util.concurrent.ForkJoinPool@5674cd4d[Running, parallelism = 15, size = 0, active = 0, running = 0, steals = 0, tasks = 0, submissions = 0]

newIncompleteFuture

java 复制代码
public <U> CompletableFuture<U> newIncompleteFuture() {
    return new CompletableFuture<U>();
}

返回一个新的未完成的 CompletableFuture。此方法在子类化 CompletableFuture 时特别有用,主要是因为它在几乎所有返回新 CompletionStage 的方法中内部使用,允许子类控制这些方法返回的子类型。

copy

java 复制代码
public CompletableFuture<T> copy()

将前一阶段的 CompletableFuture 复制为一个新的 CompletableFuture。未调用 complete()completeExceptionally()cancel()obtrudeValue()obtrudeException()completeAsync()orTimeout()completeOnTimeout() 等方法手动完成时的默认行为是:

  • 如果前一阶段正常完成,则此阶段也会以相同的返回值完成。

  • 如果前一阶段异常完成,则此阶段也会以相同的 CompletionException 异常完成。

  • 当此阶段执行时,前一阶段的任务逻辑不会再被执行一遍,copy() 等价于 thenApply(x -> x)

此方法可用于"防御性复制",避免后续操作对于原实例的修改(例如调用上述手动完成的方法),同时仍能在 CompletableFuture 实例上安排后续的依赖操作。

防御性复制

假设在下单时,保存完订单信息后发送 MQ。

java 复制代码
static void placeOrder() {
    CompletableFuture<Integer> saveOrderFuture = saveOrder();
}

static CompletableFuture<Integer> saveOrder() {
    // saveOrder
    CompletableFuture<Integer> saveOrderFuture = CompletableFuture.supplyAsync(() -> {
        int orderId = 1;
        IO.println("start saveOrder: " + orderId);

        Utils.sleep(1);

        IO.println("completed saveOrder: " + orderId);
        return orderId;
    });

    // sendMQ
    sendMQ(saveOrderFuture);
    return saveOrderFuture;
}

static void sendMQ(CompletableFuture<Integer> saveOrderFuture) {
    saveOrderFuture.thenAcceptAsync(id -> IO.println("sendMQ: " + id));
}

正确的输出如下:

复制代码
start saveOrder: 1
completed saveOrder: 1
sendMQ: 1

假设有客户代码调用了 saveOrderFuture.complete(2);

java 复制代码
static void placeOrder() {
    CompletableFuture<Integer> saveOrderFuture = saveOrder();

    // !!!
    saveOrderFuture.complete(2);
}

这会导致 MQ 发送的 orderId 为错误的值 2。

复制代码
start saveOrder: 1
sendMQ: 2
completed saveOrder: 1

如果 saveOrder 使用 copy() 返回 saveOrderFuture 的副本就可以避免上述的错误:

java 复制代码
static CompletableFuture<Integer> saveOrder() {
    // saveOrder
    CompletableFuture<Integer> saveOrderFuture = CompletableFuture.supplyAsync(() -> {
        int orderId = 1;
        IO.println("start saveOrder: " + orderId);

        Utils.sleep(1);

        IO.println("completed saveOrder: " + orderId);
        return orderId;
    });

    // sendMQ
    sendMQ(saveOrderFuture);
    // copy
    return saveOrderFuture.copy();
}
复制代码
start saveOrder: 1
completed saveOrder: 1
sendMQ: 1

测试正常完成

java 复制代码
static void test1() throws ExecutionException, InterruptedException {
    CompletableFuture<Object> f1 = CompletableFuture.supplyAsync(() -> {
        IO.println("task running");

        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

        return new Object();
    });

    CompletableFuture<Object> f2 = f1.copy();

    Object r1 = f1.get();
    Object r2 = f2.get();
    IO.println("f1 result: " + r1);
    IO.println("f2 result: " + r2);
    IO.println("r1 == r2: " + (r1 == r2));

    IO.println("f1 state: " + f1.state());
    IO.println("f2 state: " + f2.state());
}

task running 只打印了一次,说明任务逻辑不会被重复执行。

r1 == r2: true 说明新老 CompletableFuture 共享返回值。

新老 CompletableFuture 状态都是 SUCCESS。

复制代码
task running
f1 result: java.lang.Object@38af3868
f2 result: java.lang.Object@38af3868
r1 == r2: true
f1 state: SUCCESS
f2 state: SUCCESS

测试异常完成

java 复制代码
static void test2() {
    CompletableFuture<Object> f1 = CompletableFuture.supplyAsync(() -> {
        IO.println("task running");

        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

        throw new RuntimeException("timestamp: " + System.currentTimeMillis());
    });

    CompletableFuture<Object> f2 = f1.copy();

    Throwable e1 = getException(f1);
    Throwable e2 = getException(f2);

    IO.println("f1 result: " + e1);
    IO.println("f2 result: " + e2);
    IO.println("e1 == e2: " + (e1 == e2));
    IO.println("e1.cause == e2.cause: " + (e1.getCause() == e2.getCause()));

    IO.println("f1 state: " + f1.state());
    IO.println("f2 state: " + f2.state());
}

static Throwable getException(CompletableFuture<?> f1) {
    try {
        f1.join();
    } catch (Exception e) {
        return e;
    }
    throw new IllegalStateException();
}
复制代码
task running
f1 result: java.util.concurrent.CompletionException: java.lang.RuntimeException: timestamp: 1768455576415
f2 result: java.util.concurrent.CompletionException: java.lang.RuntimeException: timestamp: 1768455576415
e1 == e2: true
e1.cause == e2.cause: true
f1 state: FAILED
f2 state: FAILED

task running 同样只打印了一次,说明任务逻辑不会被重复执行。

e1 == e2: true 和 e1.cause == e2.cause: true 说明新老 CompletableFuture 共享返回的异常对象。

新老 CompletableFuture 状态都是 FAILED。

minimalCompletionStage

java 复制代码
public CompletionStage<T> minimalCompletionStage() 

将接口从 CompletableFuture 转换成了 CompletionStage,无法调用 CompletableFuture 的特有方法了。返回的 CompletionStage 的行为与上述 copy() 方法描述的相同。

返回的 CompletionStage 实际是 java.util.concurrent.CompletableFuture.MinimalStage 的实例,对 CompletableFuture 的特有方法都直接抛出了 UnsupportedOperationException 异常。

minimalCompletionStage() 的返回值强制转换为 CompletableFuture 调用相关方法,直接抛出 UnsupportedOperationException 异常

java 复制代码
static void main() throws ExecutionException, InterruptedException {
    CompletableFuture<String> future = CompletableFuture.completedFuture("ok");
    CompletionStage<String> stage = future.minimalCompletionStage();

    ((CompletableFuture<String>) stage).get();
}
复制代码
Exception in thread "main" java.lang.UnsupportedOperationException
	at java.base/java.util.concurrent.CompletableFuture$MinimalStage.get(CompletableFuture.java:2973)
	at com.zbs.jdk.MinimalCompletionStageTest.main(MinimalCompletionStageTest.java:19)

调用 toCompletableFuture() 方法可返回新的包含所有方法的完整 CompletableFuture

java 复制代码
static void main() throws ExecutionException, InterruptedException {
    CompletableFuture<String> future = CompletableFuture.completedFuture("ok");
    CompletionStage<String> stage = future.minimalCompletionStage();

    IO.println(stage.toCompletableFuture().get());
}
复制代码
ok

completeAsync

java 复制代码
public CompletableFuture<T> completeAsync(Supplier<? extends T> supplier);

public CompletableFuture<T> completeAsync(Supplier<? extends T> supplier,
                                          Executor executor);

complete() 方法的异步版本,若 CompletableFuture 还未完成,则以 supplier 的结果完成它。

测试未完成的情况

java 复制代码
static void main() throws ExecutionException, InterruptedException {
    CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
        IO.println("task1 start");
        Utils.sleep(2);
        IO.println("task1 complete");
        return "r1";
    });

    future.completeAsync(() -> {
        IO.println("task2 start");
        Utils.sleep(1);
        IO.println("task2 complete");
        return "r2";
    });

    IO.println(future.get());

    Utils.sleep(3);
}

由于 future sleep 2s,completeAsync 的任务执行时 future 还未完成,所以最终的值为 r2。

java 复制代码
task1 start
task2 start
task2 complete
r2
task1 complete

如果 supplier 抛出异常,future 同样会以异常完成。

java 复制代码
static void main() throws ExecutionException, InterruptedException {
    CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
        IO.println("task1 start");
        Utils.sleep(1);
        IO.println("task1 complete");
        return "r1";
    });

    future.completeAsync(() -> {
        throw new RuntimeException("error");
    });

    IO.println(future.get());

    Utils.sleep(3);
}
复制代码
task1 start
Exception in thread "main" java.util.concurrent.ExecutionException: java.lang.RuntimeException: error
	at java.base/java.util.concurrent.CompletableFuture.wrapInExecutionException(CompletableFuture.java:345)
	at java.base/java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:440)
	at java.base/java.util.concurrent.CompletableFuture.get(CompletableFuture.java:2094)
	at com.zbs.jdk.CompleteAsyncTest.main(CompleteAsyncTest.java:46)
Caused by: java.lang.RuntimeException: error
	at com.zbs.jdk.CompleteAsyncTest.lambda$main$1(CompleteAsyncTest.java:43)
	at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1789)
	at java.base/java.util.concurrent.CompletableFuture$AsyncSupply.exec(CompletableFuture.java:1781)
	at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:511)
	at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1450)
	at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:2019)
	at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:187)

测试已完成的情况

如果在调用 completeAsync(supplier) 方法时,future 已经完成了,则 supplier 逻辑不会执行。

java 复制代码
static void main() throws ExecutionException, InterruptedException {
    CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
        IO.println("task1 start");
        IO.println("task1 complete");
        return "r1";
    });

    IO.println(future.get());

    future.completeAsync(() -> {
        IO.println("task2 start");
        Utils.sleep(1);
        IO.println("task2 complete");
        return "r2";
    });

    IO.println(future.get());

    Utils.sleep(3);
}
复制代码
task1 start
task1 complete
r1
r1

如果在调用 completeAsync(supplier) 方法时,future 还未完成了,则 supplier 逻辑会执行。但当 supplier 执行结束时 future 已经完成了则不会对已有的结果 r1 进行修改。

java 复制代码
static void main() throws ExecutionException, InterruptedException {
    CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
        IO.println("task1 start");
        Utils.sleep(1);
        IO.println("task1 complete");
        return "r1";
    });

    future.completeAsync(() -> {
        IO.println("task2 start");
        Utils.sleep(2);
        IO.println("task2 complete");
        return "r2";
    });

    IO.println(future.get());

    Utils.sleep(3);
}
复制代码
task1 start
task2 start
task1 complete
r1
task2 complete

orTimeout、completeOnTimeout

java 复制代码
public CompletableFuture<T> orTimeout(long timeout, TimeUnit unit);

public CompletableFuture<T> completeOnTimeout(T value, long timeout, TimeUnit unit)

orTimeout: 若 CompletableFuture 在超时时间内未完成的话,则以抛出 TimeoutException 异常的方式完成。

completeOnTimeout: 若 CompletableFuture 在超时时间内未完成的话,则以 value 值完成。

orTimeout 未完成

抛出 TimeoutException

java 复制代码
static void test1() throws ExecutionException, InterruptedException {
    CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
        Utils.sleep(2);
        return "ok";
    });

    future.orTimeout(1, TimeUnit.SECONDS);

    IO.println(future.get());
}
复制代码
Exception in thread "main" java.util.concurrent.ExecutionException: java.util.concurrent.TimeoutException
	at java.base/java.util.concurrent.CompletableFuture.wrapInExecutionException(CompletableFuture.java:345)
	at java.base/java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:440)
	at java.base/java.util.concurrent.CompletableFuture.get(CompletableFuture.java:2094)
	at com.zbs.jdk.TimeoutTest.test1(TimeoutTest.java:28)
	at com.zbs.jdk.TimeoutTest.main(TimeoutTest.java:16)
Caused by: java.util.concurrent.TimeoutException
	at java.base/java.util.concurrent.CompletableFuture$Timeout.run(CompletableFuture.java:2828)
	at java.base/java.util.concurrent.DelayScheduler$ScheduledForkJoinTask.compute(DelayScheduler.java:510)
	at java.base/java.util.concurrent.ForkJoinTask$InterruptibleTask.exec(ForkJoinTask.java:1659)
	at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:511)
	at java.base/java.util.concurrent.DelayScheduler.loop(DelayScheduler.java:325)
	at java.base/java.util.concurrent.DelayScheduler.run(DelayScheduler.java:221)

orTimeout 已完成

无影响

java 复制代码
static void test2() throws ExecutionException, InterruptedException {
    CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
        Utils.sleep(1);
        return "ok";
    });

    future.orTimeout(2, TimeUnit.SECONDS);

    IO.println(future.get());
}
复制代码
ok

completeOnTimeout 未完成

以新的结果 timeout 完成

java 复制代码
static void test1() throws ExecutionException, InterruptedException {
    CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
        Utils.sleep(2);
        return "ok";
    });

    future.completeOnTimeout("timeout", 1, TimeUnit.SECONDS);

    IO.println(future.get());
}
复制代码
timeout

completeOnTimeout 已完成

以原结果 ok 完成

java 复制代码
static void test2() throws ExecutionException, InterruptedException {
    CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
        Utils.sleep(1);
        return "ok";
    });

    future.completeOnTimeout("timeout", 2, TimeUnit.SECONDS);

    IO.println(future.get());
}
复制代码
ok

static delayedExecutor

java 复制代码
public static Executor delayedExecutor(long delay, TimeUnit unit);

public static Executor delayedExecutor(long delay, TimeUnit unit, Executor executor);

返回一个新的延迟执行器,该延迟执行器在给定的延迟后向给定的执行者 executor(未指定则默认为 ASYNC_POOL)提交任务。

延迟 2s 的

java 复制代码
static void main() {
    ExecutorService executor = Executors.newCachedThreadPool();
    Executor delayedExecutor = CompletableFuture.delayedExecutor(2, TimeUnit.SECONDS, executor);

    IO.println(LocalDateTime.now());
    delayedExecutor.execute(() -> IO.println(LocalDateTime.now()));

    Utils.sleep(3);
}
复制代码
2026-01-16T14:11:15.548298700
2026-01-16T14:11:17.550877600

错误用法

==不能使用 executor.shutdown();executor.awaitTermination(3, TimeUnit.SECONDS); 等待所有任务执行完成。==因为执行 delayedExecutor.execute() 时任务并没有直接提交到 executor 中,而是提交到了中转的 ASYNC_POOL 中,等超时时间到了再提交到 executor 中。所以提前执行 executor.shutdown();executor 就无法接受任务了。

java 复制代码
static void main() throws InterruptedException {
    ExecutorService executor = Executors.newCachedThreadPool();
    Executor delayedExecutor = CompletableFuture.delayedExecutor(2, TimeUnit.SECONDS, executor);

    IO.println(LocalDateTime.now());
    delayedExecutor.execute(() -> IO.println(LocalDateTime.now()));

    executor.shutdown();
    executor.awaitTermination(3, TimeUnit.SECONDS);
}
复制代码
2026-01-16T14:26:54.112797900

delayedExecutor 作为 CompletableFuture 的执行器

delayedExecutor 和普通的 Executor 一样,也可以作为 CompletableFuture 的执行器。

java 复制代码
static void main() throws ExecutionException, InterruptedException {
    ExecutorService executor = Executors.newCachedThreadPool();
    Executor delayedExecutor = CompletableFuture.delayedExecutor(2, TimeUnit.SECONDS, executor);

    IO.println(LocalDateTime.now());
    CompletableFuture<LocalDateTime> future = CompletableFuture.supplyAsync(
            LocalDateTime::now, delayedExecutor);

    IO.println(future.get());
}
复制代码
2026-01-16T14:44:19.951428500
2026-01-16T14:44:21.953452400

static completedStage、failedFuture、failedStage

java 复制代码
// jdk8 已存在
public static <U> CompletableFuture<U> completedFuture(U value);

public static <U> CompletableFuture<U> failedFuture(Throwable ex);

completedFuture: 返回一个已经以指定的 value 正常完成的 CompletableFuture

failedFuture: 返回一个已经以指定的 ex 异常完成的 CompletableFuture

java 复制代码
public static <U> CompletionStage<U> completedStage(U value);

public static <U> CompletionStage<U> failedStage(Throwable ex);

同上,与 minimalCompletionStage 类似,返回的是 CompletionStage 类型。

CompletableFuture jdk12

exceptionallyAsync

java 复制代码
// jdk8 已存在
public CompletableFuture<T> exceptionally(
        Function<Throwable, ? extends T> fn);

public CompletableFuture<T> exceptionallyAsync(
    Function<Throwable, ? extends T> fn);

public CompletableFuture<T> exceptionallyAsync(
    Function<Throwable, ? extends T> fn, Executor executor);
  • 当前一个阶段抛出异常时才会执行本阶段,并将抛出的异常作为参数传入;

  • 若前一个阶段正常完成则不执行 fn 逻辑且返回值和前一个阶段的相同。

类似 Stream.map()

注意: Function fn 返回值类型必须和前一阶段的一致,都是 T

传入 fn 的异常可能是 CompletionException 类型,要获取原异常需要调用 e.getCause()

前一个阶段报错的情况

java 复制代码
static void test1() throws Exception {
    CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
        throw new RuntimeException("stage 1 error");
    });
    CompletableFuture<String> future2 = future1.exceptionallyAsync(e -> {
        IO.println("The previous stage exception:" + e);
        Throwable cause = e;
        if (e instanceof CompletionException) {
            cause = e.getCause();
        }

        IO.println("The previous stage exception cause:" + cause);
        return "exceptionally stage";
    });
    IO.println(future2.get());
}
复制代码
The previous stage exception:java.util.concurrent.CompletionException: java.lang.RuntimeException: stage 1 error
The previous stage exception cause:java.lang.RuntimeException: stage 1 error
exceptionally stage

前一个阶段未报错的情况

java 复制代码
static void test2() throws Exception {
    CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "stage 1 ok");
    CompletableFuture<String> future2 = future1.exceptionallyAsync(e -> {
        IO.println("The previous stage exception:" + e);
        Throwable cause = e;
        if (e instanceof CompletionException) {
            cause = e.getCause();
        }

        IO.println("The previous stage exception cause:" + cause);
        return "exceptionally stage";
    });
    IO.println(future2.get());
}
复制代码
stage 1 ok

exceptionallyCompose、exceptionallyComposeAsync

exceptionallyAsync 类似只是 Function fn 的返回值从 T 变成了 CompletionStage<T>

  • 当前一个阶段抛出异常时才会执行本阶段,并将抛出的异常作为参数传入;

  • 若前一个阶段正常完成则不执行 fn 逻辑且返回值和前一个阶段的相同。

类似 Stream.flatMap()

注意: Function fn 的返回的 CompletionStage 的泛型必须和前一阶段的返回值类型一致,都是 T

java 复制代码
public CompletableFuture<T> exceptionallyCompose(
    Function<Throwable, ? extends CompletionStage<T>> fn);

public CompletableFuture<T> exceptionallyComposeAsync(
    Function<Throwable, ? extends CompletionStage<T>> fn);

public CompletableFuture<T> exceptionallyComposeAsync(
    Function<Throwable, ? extends CompletionStage<T>> fn,
    Executor executor);

适用于要返回的值需要从另一个 CompletableFuture 获取的情况,如下的示例:

前一个阶段报错的情况

java 复制代码
static void test1() throws Exception {
    CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
        throw new RuntimeException("task error");
    });
    CompletableFuture<String> future2 = future1.exceptionallyComposeAsync(e -> {
        IO.println("The previous stage exception:" + e);
        Throwable cause = e;
        if (e instanceof CompletionException) {
            cause = e.getCause();
        }

        IO.println("The previous stage exception cause:" + cause);
        return retryTask();
    });
    IO.println(future2.get());
}

static CompletableFuture<String> retryTask() {
    return CompletableFuture.supplyAsync(() -> {
        IO.println("retrying task");
        return "retry task result";
    });
}
复制代码
The previous stage exception:java.util.concurrent.CompletionException: java.lang.RuntimeException: task error
The previous stage exception cause:java.lang.RuntimeException: task error
retrying task
retry task result

前一个阶段未报错的情况

java 复制代码
static void test2() throws Exception {
    CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "task ok");
    CompletableFuture<String> future2 = future1.exceptionallyComposeAsync(e -> {
        IO.println("The previous stage exception:" + e);
        Throwable cause = e;
        if (e instanceof CompletionException) {
            cause = e.getCause();
        }

        IO.println("The previous stage exception cause:" + cause);
        return retryTask();
    });
    IO.println(future2.get());
}
复制代码
task ok

参考

  1. Java异步执行器CompletableFuture(Jdk9)改进 - 夏尔_717 - 博客园
  2. CompletableFuture API 过于复杂?选取7个最常用的方法,解决95%的问题截止 JDK25,Compl - 掘金
  3. 如何安全发布 CompletableFuture ?Java9新增方法分析 - 个人文章 - SegmentFault 思否
  4. Java 9 CompletableFuture API 改进 | Baeldung中文网
  5. 深入理解 Future, CompletableFuture, ListenableFuture,回调机制分析了Futu - 掘金
相关推荐
wanghowie18 天前
02.02.02 CompletableFuture 组合与异常处理:构建复杂异步流
java·future·并发编程
亚林瓜子2 个月前
Spring中的异步任务(CompletableFuture版)
java·spring boot·spring·async·future·异步
寒水馨6 个月前
Java 9 新特性解析
java·开发语言·新特性·java9·jdk9
茶本无香9 个月前
CompletableFuture:整合、超时、完成事件与批量处理
java·超时·future·completable·completion·任务整合
茶本无香9 个月前
Java异步编程中的CompletableFuture介绍、常见错误及最佳实践
java·future·异步·常见错误
10km1 年前
java:修复aspectj-maven-plugin插件在java9项目中执行报错:cannot be resolved to a module
java·plugin·module-info·aspectj·jdk9
无休居士1 年前
Java8中CompletableFuture.allOf的使用
android·java·开发语言·future·completable·allof
10km1 年前
javdoc:(JDK9)VISITOR模式遍历语法树(DocCommentTree)获取代码注释中的tag(@return,@param)对象
java·访问者模式·javadoc·jdk9·doccommenttree·doctreevisitor
iFlyCai1 年前
Flutter中的异步编程
flutter·stream·async·future·await·futurebuilder·flutter异步编程