2017-10-30 10 views
3

私の直感は、次のコードが間違っているということです。私は、join()が使用されているので、未来が完了していない間は例外がスローされます。次にget()が呼び出されると、チェックされた例外はなく、エラーのログもなく、失敗時のエラーの診断が難しくなります。join()とget()のCompletableFuture例外動作

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のドキュメントを見てきましたが、私の質問に対する正確な答えが見つかりませんでした。私はここで尋ねて、ソースコードを読んで行くでしょう。

キャッチブロックコードが実行されることがわかっているのは、何らかのチェック例外がいくつかの実行コンテキストに保存され、join()(またはチェックされていない例外によってラップされる)にスローされず、いくつかの形式でget()の後に。これは私にはそう思わない。

私の究極の質問は、キャッチブロックコードはこれまで実行されていますか?

+1

なぜ単に直接使用するだけではありません: 'CompletableFuture.allOf(new CompletableFuture [] {future1、future2})。join();' – Lino

+0

@Lino共有コードベースで作業していますが、これは私のコードではありません。 – user3527174

+1

はもっと簡単であることが分かった: 'CompletableFuture.allOf(future1、future2).join();' – Lino

答えて

3

joinget方法の両方が完了信号に依存しており、その結果Tを返すメソッドをブロックしています。問題のように、コードの一部を処理: - 私たちはgetがそうであるようにスレッドが待っているの過程で中断している間

一方

InterruptedExceptionがスローされる可能性が、ここでの待ち時間はすでに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. 
*/ 

のでjoinメソッドのドキュメントに記載されているようにし、将来が非常に完了した場合とき

また、あなたのケースでfutureN.get()ためExecutionExceptionにのみスローされる可能性。例外的に実行された場合、将来はjoin呼び出しのためにCompletionExceptionが投げられることになるので、それは今までcatchブロックに到達していなかったか、tryブロックのいずれかに到達しませんでした。

0

はい、コードには到達しませんが、「コードが間違っていません」。

まず、あなたがtry/catch「* 1」を行っていないので、例外は、メソッドが終了してしまうとget()に到達することはないでしょう

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!"); 
    } 

...ちょうどそれを試してみましょう。 2番目の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"); 
    } 
関連する問題