[英]Why is the result of this code non-deterministic?
I would expect the following code to always print "Errored", but sometimes it prints "outerinner".我希望下面的代码总是打印“Errored”,但有时它会打印“outerinner”。 What I want to happen is for "outer" to complete and for "inner" to use "outer"'s result to generate its own result, failing if either future fails.我想要发生的是“外部”完成和“内部”使用“外部”的结果来生成自己的结果,如果未来失败则失败。 What am I doing wrong?我究竟做错了什么?
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");
}
It's actually fairly trivial to understand this one.理解这一点实际上是相当微不足道的。 You need to look more closely at this:你需要更仔细地看看这个:
CompletableFuture<String> inner = CompletableFuture.supplyAsync(() -> "inner");
specifically the fact that you are saying supplyAsync
, which means in a different thread .特别是您说的是supplyAsync
,这意味着在不同的线程中。 While in your main thread (or any other) you do : inner.completeExceptionally(new IllegalArgumentException());
在您的主线程(或任何其他线程)中,您执行以下操作: inner.completeExceptionally(new IllegalArgumentException());
. .
Which thread is supposed to win?哪个线程应该获胜? The one from supplyAsync
or the one where you run inner.completeExceptionally
?来自supplyAsync
还是你运行inner.completeExceptionally
? Of course, the documentation of completeExceptionally
mentions this... It's a basic "race", which thread reaches to "complete" (either normally or via an Exception) that inner
first.当然,的文档completeExceptionally
提到了这一点......这是一个基本的“种族”,哪个线程达到“完全”(正常或通过一个例外),其inner
第一。
The key to understanding what is going on is in the javadoc for completeExceptionally
.理解发生了什么的关键是在completeExceptionally
的javadoc中。
If not already completed , causes invocations of
get()
and related methods to throw the given exception.如果尚未完成,则导致调用get()
和相关方法抛出给定的异常。
In your example, you are creating two futures which will be completed asynchronously, then you are calling completeExceptionally
to tell one of the futures to throw an exception rather than delivering a result.在您的示例中,您正在创建两个将异步完成的期货,然后您调用completeExceptionally
以告诉其中一个期货抛出异常而不是提供结果。
Based on what you are saying, it appears that sometimes the inner
future has already completed by the time you call completeExceptionally
.根据您所说的,有时在您调用completeExceptionally
时, inner
未来似乎已经completeExceptionally
。 In that case, the completeExceptionally
call will have no affect (as per the spec), and the subsequent inner.get()
will deliver the result that was (already) computed.在这种情况下, completeExceptionally
调用将没有影响(根据规范),随后的inner.get()
将提供(已经)计算的结果。
It is a race condition.这是一个竞争条件。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.