completeExceptionally 和 obtrudeException 的区别

Difference between completeExceptionally and obtrudeException

刚刚浏览了 CompletableFuture 文档,偶然发现了 completeExceptionally and obtrudeException 方法,很难理解其中的区别和用例。社区能否通过示例帮助理解差异和用例?

异常完成:

completableFuture.completeExceptionally(
  new RuntimeException("Calculation failed!"));
//.. 
completableFuture.get(); //exception will be thrown whether `completableFuture` was not already completed.

obtrudeException:

completableFuture.obtrudeException(
  new RuntimeException("Calculation failed!"));
//.. 
completableFuture.get(); //exception will be thrown **whether or not** `completableFuture` was completed.

说明

区别很微妙但很重要。来自 official documentation:

If not already completed, causes invocations of get() and related methods to throw the given exception.

Forcibly causes subsequent invocations of method get() and related methods to throw the given exception, whether or not already completed. [...]

所以他们在 CompletableFuture 方面的行为不同 已经完成

基本上,未来可以是已完成,也可以是待定(未完成)。当您调用 completeExceptionallyobtrudeException 时,行为会根据该时间点的未来状态而有所不同。


已经完成的未来

考虑这个例子,在调用方法时 future 已经完成:

CompletableFuture<String> future = CompletableFuture.completedFuture("hello world");

future.completeExceptionally(new RuntimeException("Oh noes!"));
System.out.println(future.get()); // Prints "hello world" just fine

对比

CompletableFuture<String> future = CompletableFuture.completedFuture("hello world");

future.obtrudeException(new RuntimeException("Oh noes!"));
System.out.println(future.get()); // Throws the exception

未完成的未来

如果 future 还没有完成,它们都会抛出异常:

CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> { 
    try {
        Thread.sleep(5000);
    } catch (InterruptedException e) {
    }
    return "hello world";
});

future.completeExceptionally(new RuntimeException("Oh noes!"));
System.out.println(future.get());

CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> { 
    try {
        Thread.sleep(5000);
    } catch (InterruptedException e) {
    }
    return "hello world";
});

future.obtrudeException(new RuntimeException("Oh noes!"));
System.out.println(future.get());

completeobtrudeValue

同样,还有一些方法 complete and obtrudeValue 的行为方式相同,但不是抛出异常,而是提供一个值。

所以complete基本上是用给定的值完成未来,如果未来还没有完成,否则什么都不做。

虽然 obtrudeValue 无论如何都会提供给定值,因此它会重置或取消任何已经计算的未来,并用给定值替换它。