java - 如果手动完成,则不会调用 CompletableFuture 回调

标签 java completable-future

在这个CompletableFuture的基本示例中,我异步运行一个任务,当它完成时,应该触发一个异步回调。

在我开始运行任务后一秒,在任务完成之前,我完成了它。之后我就看不到它再运行异步回调了。

public static void main(String[] args) throws InterruptedException {
    runTask();
    Thread.sleep(1000);
    completableFuture.complete("Test");
    Thread.sleep(4000);
}

public static void runTask() {
    completableFuture = CompletableFuture.supplyAsync(() -> {
        System.out.println("Running...");
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("...finished");
        return "finished task";
    })
    .thenApplyAsync(s -> {
        System.out.println("Apply on result: " + s);
        return "Result: " + s;
    })
}

结果是:

Running...
...finished

问题是,如果我添加另一个回调,那么它会运行第一个回调,但不会运行第二个回调。

.thenApplyAsync(s -> {
    System.out.println("Second apply with result: " + s);
    return "Result: " + s;
})

那么结果是:

Running...
...finished
Apply on result: finished task

阅读文档后,我明白所有回调都会被调用,即使 future 是手动完成的。我在这里遗漏了什么吗?

最佳答案

我想如果你的写法稍微不同,它应该是有意义的:

public static void runTask() {

    CompletableFuture<String> one = CompletableFuture.supplyAsync(() -> {
        System.out.println("Running...");
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("...finished");
        return "finished task";
    });

    CompletableFuture<String> two = one.thenApplyAsync(s -> {
        System.out.println("Apply on result: " + s);
        return "Result: " + s;
    });

    completableFuture = two;
} 

所以,one在你的情况下开始很好,但在 two 之前甚至可以启动,您发出 completableFuture.complete("Test"); 。那么当 one完成后,没有什么可以做的thenApplyAsync ,因为那个已经完成了。

当你再添加一个阶段时,你基本上会得到:

....
CompletableFuture<String> two = one.thenApplyAsync(s -> {
     System.out.println("Apply on result: " + s);
     return "Result: " + s;
});

CompletableFuture<String> three = two.thenApplyAsync(s -> {
     System.out.println("Second apply with result: " + s);
     return "Result: " + s;
});

completableFuture = three;

不用我解释,你也许就能明白这里发生了什么。


为此,我看不出文档在哪里可以清楚地说明这一点。我想我们需要在 package documentation 中看到这一点,通过:

When two or more threads attempt to complete, completeExceptionally, or cancel a CompletableFuture, only one of them succeeds.

这在某种程度上意味着,如果某个阶段尚未开始,但外部有其他人 complete是它;那个阶段根本不会运行。这是有道理的,但在我看来,包文档可以更清晰。

关于java - 如果手动完成,则不会调用 CompletableFuture 回调,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66250511/

相关文章:

java - Java 中的多线程,跟踪成功和失败的任务

java - Espresso 不等待 AsyncTask 完成

用于 JSON 通信和 DOM 操作的 javascript 框架?

java - 为什么 CompletableFuture 中的断点也会停止主线程中的执行?

java - 从 CompletableFuture 调用 ExecutorService.shutdownNow

java - 引用 CompletableFuture 中的字段,它又可以是 CompletableFuture : java

Java 使用 List<CustomObjects> 重写构造函数 - "same erasure"错误

java - 使用java模拟并发更新计数

java - 分枝效率

Kotlin supplyAsync with executor