【发布时间】:2018-10-19 06:40:04
【问题描述】:
我写了一个方法如下:
public static CompletionStage<Tuple2<ObjectNode, String>> calculateTemplateTreeAndKeys(
String content,
RequestContext context,
MetricsClient metricsClient,
JdbcSession jdbcSession) {
AtomicReference<ObjectNode> templateTreeHolder = new AtomicReference<>();
templateTreeHolder.set(Json.rootNode());
return getTemplateIds(context, metricsClient, jdbcSession, content)
.thenCompose(
templateIds -> {
templateIds.map(
id ->
// do something and return CompletionStage<String>
.thenAccept(
tree -> {
templateTreeHolder.set(
(ObjectNode)
templateTreeHolder.get().set(id, Json.readTree(tree)));
System.out.println(
"From inner function: " + templateTreeHolder.get());
}));
return CompletableFuture.completedFuture(NotUsed.getInstance());
})
.thenApply(
notUsed -> {
String includedTemplateIdsStr =
getKeysFromTemplateTree(templateTreeHolder.get()).toJavaList().toString();
System.out.println("From outer function: " + templateTreeHolder.get());
return Tuple.of(templateTreeHolder.get(), includedTemplateIdsStr);
});
我希望内部块在之前处理和更新 templateTreeHolder .thenApply 被调用,因此 templateTreeHolder 将保存正确的数据以返回。但是,.thenApply 块在内部 .thenAccept 块之前处理。
从控制台输出序列:
From outer function: {}
From inner function: {"f9406341-c62a-411a-9389-00a62bd63629":{}}
我不确定我在链接 CompletionStages 时做错了什么,请告诉我如何确保内部块在外部块之前完成?
【问题讨论】:
-
首先,我认为你的例子太复杂了。其次,你没有使用任何
async方法,为什么你甚至需要像这样进行链接? -
@Jai 该项目基于事件溯源/CQRS,我们需要确保每个事件在下一个之前处理,因此有意避免任何异步方法。我对为什么 .thenApply 在 .thenAccept 之前运行以及如何避免这种情况感到困惑。
-
如果他们需要顺序运行,那么只需删除内部的
CompletableFuture。那不是更容易吗?我想不出任何理由CompletableFuture会在非异步上下文中做任何有用的事情。 -
@Jai 感谢您的建议,但目前不可能,代码库与基于 Lagom、akka 持久性、Vavr 库的 CompletionStages 捆绑在一起。无论如何,如果你能就这个确切的问题提出一些建议,那将会很有帮助。
-
你得到你想要的。当
CompletableFuture.completedFuture(NotUsed.getInstance())完成时,评估最后一个函数。我们无法知道传递给templateIds.map(…)的函数何时被评估,因为它与您的其余代码(尤其是完成阶段链)完全无关。
标签: java multithreading asynchronous java-8 java.util.concurrent