java - 推迟 thenApplyAsync 执行

标签 java java-8 completable-future

我有以下场景。

CompletableFuture<T> result = CompletableFuture.supplyAsync(task, executor);
result.thenRun(() -> {
        ...
    });
// ....
// after some more code, based on some condition I attach the thenApply() to result.

if ( x == 1) {
    result.thenApplyAsync(t -> {

        return null;
    });
}

问题是,如果 CompletableFuture 线程在主线程到达 thenApplyAsync 之前完成执行会怎样? CompletableFuture 结果是否应将其自身附加到 thenApply。即应该在定义 CompletableFuture.supplyAsync() 本身时声明回调吗?

还有执行顺序是什么? thenRun() 总是最后执行(在 thenApply() 之后)?

使用此策略有什么缺点吗?

最佳答案

您似乎忽略了重要的一点。当您链接依赖函数时,您不会改变调用链接方法的 future 。

相反,这些方法中的每一个都会返回一个代表相关操作的完成阶段。

由于您将两个依赖操作附加到 result,它们代表传递给 supplyAsynctask,因此这两个操作之间没有关系。它们可以以任意顺序运行,甚至可以同时在不同的线程中运行。

由于您没有将 thenApplyAsync 返回的 future 存储在任何地方,因此其评估结果无论如何都会丢失。假设您的函数返回与 T 类型相同的结果,您可以使用

if(x == 1) {
    result = result.thenApplyAsync(t -> {

        return null;
    });
}

将可能完成的 future 替换为新的 future ,该新的 future 仅在评估指定函数的结果时才完成。通过 thenRun 在原始 future 注册的可运行对象仍然不依赖于这个新的 future。请注意,没有执行器的 thenApplyAsync 将始终使用默认执行器,无论使用哪个执行器来完成另一个 future。

如果您想确保Runnable在任何其他阶段之前已成功执行,您可以使用

CompletableFuture<T> result = CompletableFuture.supplyAsync(task, executor);
CompletableFuture<Void> thenRun = result.thenRun(() -> {
    //...
});
result = result.thenCombine(thenRun, (t,v) -> t);

另一种选择是

result = result.whenComplete((value, throwable) -> {
    //...
});

但是在这里,即使在特殊情况下(包括取消),代码也将始终执行。如果您只想在成功的情况下执行代码,则必须检查 throwable 是否为 null


如果您想确保可运行对象在两个操作之后运行,最简单的策略是在定义最终完成阶段时将其链接到 if 语句之后:

if(x == 1) {
    result = result.thenApplyAsync(t -> {

        return null;
    });
}
result.thenRun(() -> {
    //...
});

如果这不是一个选择,您将需要一个不完整的 future ,您可以根据任一结果完成:

CompletableFuture<T> result = CompletableFuture.supplyAsync(task, executor);

//...

CompletableFuture<T> finalStage = new CompletableFuture<>();
finalStage.thenRun(() -> {
    //...
});

// ...

if(x == 1) {
    result = result.thenApplyAsync(t -> {

        return null;
    });
}
result.whenComplete((v,t) -> {
    if(t != null) finalStage.completeExceptionally(t); else finalStage.complete(v);
});

finalStage 最初没有定义的完成方式,但我们仍然可以链接相关操作。一旦我们知道了实际的 future ,我们就可以链接一个处理程序,它将以我们得到的任何结果完成我们的 finalStage


最后一点,没有 ...Async 的方法(如 thenRun)对评估线程提供的控制最少。它们可能会在未来完成的任何线程中执行,例如示例中的 executor 线程之一,但也可以直接在调用 thenRun 的线程中执行,甚至不太直观,在您的原始示例中,可运行对象可能会在不相关的 thenApplyAsync 调用期间执行。

关于java - 推迟 thenApplyAsync 执行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50735686/

相关文章:

Java CompletionStage 到 CompletionStage<Either> 类型丢失

java - Future Cancel 是否也会终止数据库端的 Oracle 查询

java - 访问 map map 的最佳方式

java - 如何在录音时为语音留言设置定时器(与 WhatsApp 语音留言录音功能相同)?

java - 未报告的异常处理

java - java8中如何在LocalDateTime、ZonedDateTime等类中选择Date/Time类?

java - 未处理的异常在两种不同的方法上的工作方式不同

multithreading - AsyncHttpClient创建多少线程?

java - 为二十一点创建人工智能

java - 将多个流优化为单个循环