推迟thenApplyAsync执行

时间:2018-06-07 07:49:31

标签: 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()之后)?

使用这种策略有什么缺点吗?

1 个答案:

答案 0 :(得分:3)

你似乎错过了一个重要的观点。当你链接一个依赖函数时,你改变未来你正在调用链接方法。

相反,这些方法中的每一个都返回一个表示依赖操作的 new 完成阶段。

由于您要将两个相关操作附加到result,表示传递给task的{​​{1}},因此这两个操作之间没有任何关系。它们可以以任意顺序运行,甚至可以在不同的线程中同时运行。

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

T

用新的未来替换潜在完成的未来,只有在评估了指定函数的结果后才能完成。通过if(x == 1) { result = result.thenApplyAsync(t -> { return null; }); } 在原始未来注册的可运行仍然不依赖于这个新的未来。请注意,没有执行程序的thenRun将始终使用默认执行程序,无论使用哪个执行程序来完成另一个未来。

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

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

如果你想确保runnable在两个动作之后运行,最简单的策略是在null语句后链接它,当定义最终完成阶段时:

if

如果这不是一个选项,那么你需要一个不完整的未来,你可以在任何一个结果上完成:

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

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

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

最后一点,没有finalStage的方法,如…Async,对评估线程的控制最少。它们可能会在未来完成的任何线程中执行,比如示例中thenRun的一个线程,但也可以直接在调用executor的线程中执行,在原始示例中,甚至不太直观, runnable可能会在无关的thenRun调用期间执行。