为什么这段代码的结果是不确定的?
Why is the result of this code non-deterministic?
我希望下面的代码总是打印“Errored”,但有时它会打印“outerinner”。我想要发生的是让“外部”完成,让“内部”使用“外部”的结果生成自己的结果,如果任何一个未来失败,都会失败。我做错了什么?
CompletableFuture<String> outer = CompletableFuture.supplyAsync(() -> "outer");
CompletableFuture<String> inner = CompletableFuture.supplyAsync(() -> "inner");
inner.completeExceptionally(new IllegalArgumentException());
CompletableFuture<String> both = outer.thenApply(s -> {
try {
String i = inner.get();
return s + i;
} catch (InterruptedException |ExecutionException e) {
throw new IllegalStateException(e);
}
});
try {
String o = both.get();
System.out.println(o);
} catch (ExecutionException | InterruptedException e) {
System.err.println("Errored");
}
了解正在发生的事情的关键在于 javadoc for completeExceptionally
。
If not already completed, causes invocations of get()
and related methods to throw the given exception.
在您的示例中,您正在创建两个异步完成的 future,然后调用 completeExceptionally
告诉其中一个 future 抛出异常而不是传递结果。
根据您所说的,有时在您调用 completeExceptionally
时 inner
未来 已经完成 。在这种情况下,completeExceptionally
调用将没有影响(根据规范),随后的 inner.get()
将提供(已经)计算的结果。
这是一个竞争条件。
理解这一点其实很简单。你需要仔细看看这个:
CompletableFuture<String> inner = CompletableFuture.supplyAsync(() -> "inner");
具体来说,您说的是 supplyAsync
,这意味着 在另一个线程中 。在您的主线程(或任何其他线程)中,您执行以下操作:inner.completeExceptionally(new IllegalArgumentException());
.
哪个线程应该获胜?来自 supplyAsync
的那个还是你 运行 inner.completeExceptionally
的那个?当然,completeExceptionally
的文档提到了这一点......这是一个基本的“竞赛”,哪个线程首先到达 inner
“完成”(通常或通过异常)。
我希望下面的代码总是打印“Errored”,但有时它会打印“outerinner”。我想要发生的是让“外部”完成,让“内部”使用“外部”的结果生成自己的结果,如果任何一个未来失败,都会失败。我做错了什么?
CompletableFuture<String> outer = CompletableFuture.supplyAsync(() -> "outer");
CompletableFuture<String> inner = CompletableFuture.supplyAsync(() -> "inner");
inner.completeExceptionally(new IllegalArgumentException());
CompletableFuture<String> both = outer.thenApply(s -> {
try {
String i = inner.get();
return s + i;
} catch (InterruptedException |ExecutionException e) {
throw new IllegalStateException(e);
}
});
try {
String o = both.get();
System.out.println(o);
} catch (ExecutionException | InterruptedException e) {
System.err.println("Errored");
}
了解正在发生的事情的关键在于 javadoc for completeExceptionally
。
If not already completed, causes invocations of
get()
and related methods to throw the given exception.
在您的示例中,您正在创建两个异步完成的 future,然后调用 completeExceptionally
告诉其中一个 future 抛出异常而不是传递结果。
根据您所说的,有时在您调用 completeExceptionally
时 inner
未来 已经完成 。在这种情况下,completeExceptionally
调用将没有影响(根据规范),随后的 inner.get()
将提供(已经)计算的结果。
这是一个竞争条件。
理解这一点其实很简单。你需要仔细看看这个:
CompletableFuture<String> inner = CompletableFuture.supplyAsync(() -> "inner");
具体来说,您说的是 supplyAsync
,这意味着 在另一个线程中 。在您的主线程(或任何其他线程)中,您执行以下操作:inner.completeExceptionally(new IllegalArgumentException());
.
哪个线程应该获胜?来自 supplyAsync
的那个还是你 运行 inner.completeExceptionally
的那个?当然,completeExceptionally
的文档提到了这一点......这是一个基本的“竞赛”,哪个线程首先到达 inner
“完成”(通常或通过异常)。