推迟 thenApplyAsync 执行
defer thenApplyAsync execution
我有以下场景。
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()
之后) ?
使用这个策略有什么缺点吗?
你似乎漏掉了一个重点。当您链接一个依赖函数时,您不会改变您调用链接方法的未来。
相反,这些方法中的每一个 returns 一个 new 完成阶段代表相关操作。
由于您将两个相关操作附加到 result
,它们表示传递给 supplyAsync
的 task
,因此这两个操作之间没有任何关系。它们可能 运行 以任意顺序甚至在不同线程中同时出现。
由于您没有将 thenApplyAsync
返回的未来存储在任何地方,因此其评估结果无论如何都会丢失。假设您的函数 returns 是与 T
相同类型的结果,您可以使用
if(x == 1) {
result = result.thenApplyAsync(t -> {
return null;
});
}
用新的未来替换可能完成的未来,新的未来只有在评估指定函数的结果时才会完成。通过 thenRun
在原始 future 注册的 运行nable 仍然不依赖于这个新的 future。注意thenApplyAsync
不带executor会一直使用默认的executor,不管其他future是用哪个executor完成的
如果你想确保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
。
如果你想确保 运行nable 运行s 在两个动作之后,最简单的策略是将它链接在 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
的线程之一,但也可能直接在调用 thenRun
的线程中执行,甚至更不直观,在您的原始示例中, 运行nable 可能会在不相关的 thenApplyAsync
调用期间执行。
我有以下场景。
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()
之后) ?
使用这个策略有什么缺点吗?
你似乎漏掉了一个重点。当您链接一个依赖函数时,您不会改变您调用链接方法的未来。
相反,这些方法中的每一个 returns 一个 new 完成阶段代表相关操作。
由于您将两个相关操作附加到 result
,它们表示传递给 supplyAsync
的 task
,因此这两个操作之间没有任何关系。它们可能 运行 以任意顺序甚至在不同线程中同时出现。
由于您没有将 thenApplyAsync
返回的未来存储在任何地方,因此其评估结果无论如何都会丢失。假设您的函数 returns 是与 T
相同类型的结果,您可以使用
if(x == 1) {
result = result.thenApplyAsync(t -> {
return null;
});
}
用新的未来替换可能完成的未来,新的未来只有在评估指定函数的结果时才会完成。通过 thenRun
在原始 future 注册的 运行nable 仍然不依赖于这个新的 future。注意thenApplyAsync
不带executor会一直使用默认的executor,不管其他future是用哪个executor完成的
如果你想确保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
。
如果你想确保 运行nable 运行s 在两个动作之后,最简单的策略是将它链接在 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
的线程之一,但也可能直接在调用 thenRun
的线程中执行,甚至更不直观,在您的原始示例中, 运行nable 可能会在不相关的 thenApplyAsync
调用期间执行。