CompletableFuture 异常行为与 join() 然后 get()

CompletableFuture exception behavior with join() then get()

我的直觉是下面的代码是错误的。我相信因为正在使用 join() ,所以在完成期货时抛出的任何异常都不会被检查。那么在调用get()时,将不会出现checked exceptions,不会记录任何错误,并且在失败时很难诊断错误。

    List<CompletableFuture> list = ImmutableList.of(future1, future2);
    CompletableFuture.allOf(list.toArray(new CompletableFuture[list.size()])).join();

    try {
        result1 = future1.get();
        result2 = future2.get();

    } catch (InterruptedException | ExecutionException e) {
        // will this ever run if join() is already called?
    }

我已经查看了 CompletableFuture 的文档,但没有找到我的问题的确切答案。我在这里问,然后去阅读源代码。

我能看到 catch 块代码 运行 的唯一原因是,是否可以以某种方式将已检查的异常保存在某些执行上下文中,而不是在 join() 中抛出(或被未检查的异常包裹抛出) ,然后在 get() 之后以某种形式再次抛出。这对我来说似乎不太可能。

所以我的最终问题是,catch 块代码会 运行 吗?

是的,永远无法到达代码,但这并不能使 "code wrong"。

首先,让我们试一试...

    CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
        throw new IllegalArgumentException();
    });
    try
    {
        CompletableFuture.allOf(future1).join();
    }
    catch (Exception e1)
    {
        System.out.println("I'd exit here."); // *1
    }

    try
    {
        future1.get();
    }
    catch (InterruptedException | ExecutionException e)
    {
        System.out.println("Entered!");
    }

由于您没有执行 try/catch "*1",异常将导致方法退出并且永远不会到达 get();所以第二个 catch 子句永远不会被执行。

但是,catch仍然是必需的,因为它是给编译器的,编译器无法知道之前的调用顺序。

无论如何,更直接的方法是这样的:

    CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
        throw new IllegalArgumentException();
    });
    try
    {
        CompletableFuture.allOf(future1).join();
        future1.get();
    }
    catch (CompletionException e1) // this is unchecked, of course
    {
        System.out.println("Exception when joining");
    }
    catch (InterruptedException | ExecutionException e)
    {
        System.out.println("Exception when getting");
    }

joinget方法都是阻塞方法,依赖于完成信号和returns结果T。处理有问题的代码:-

一方面,InterruptedException在线程等待的过程中可能会抛出get,这里的等待已经被join完成了方法。

此外,如 join 方法文档中所述

/**
 * ... if a
 * computation involved in the completion of this
 * CompletableFuture threw an exception, this method throws an
 * (unchecked) {@link CompletionException} with the underlying
 * exception as its cause.
 */

因此,另一方面,您的案例中 futureN.get()ExecutionException 只能在未来异常完成时抛出。由于未来如果异常执行将最终为 join 调用抛出 CompletionException,因此它永远不会到达 catch 块或因此 try 块。