我有以下情况。
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()
之后)?
使用这种策略有什么缺点吗?
答案 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
调用期间执行。