2016-12-27 8 views
3

テキストファイルを読み取る小さな例を作成し、CompletableFutureで呼び出しをラップしました。CompletableFutureでサプライヤを使用すると、ラムダを使用する場合とは異なる結果になる

public class Async { 
    public static void main(String[] args) throws Exception { 
     CompletableFuture<String> result = ReadFileUsingLambda(Paths.get("path/to/file")); 
     result.whenComplete((ok, ex) -> { 
      if (ex == null) { 
       System.out.println(ok); 
      } else { 
       ex.printStackTrace(); 
      } 
     }); 
    } 

    public static CompletableFuture<String> ReadFileUsingSupplier(Path file) throws Exception { 
     return CompletableFuture.supplyAsync(new Supplier<String>() { 
      @Override 
      public String get() { 
       try { 
        return new String(Files.readAllBytes(file)); 
       } catch (IOException e) { 
        e.printStackTrace(); 
        return "test"; 
       } 
      } 
     }, ForkJoinPool.commonPool()); 
    } 

    public static CompletableFuture<String> ReadFileUsingLambda(Path file) throws Exception { 
     return CompletableFuture.supplyAsync(() -> { 
      try { 
       return new String(Files.readAllBytes(file)); 
      } catch (IOException e) { 
       e.printStackTrace(); 
       return "test"; 
      } 
     } , ForkJoinPool.commonPool()); 
    } 
} 

このコードは何も返しません。それは実行し、 "何も起こらない"、エラーも出力もない。 ReadFileUsingLambdaの代わりにReadFileUsingSupplierと呼ぶと、ファイルの内容がコンソールに表示されます。

ラムダはインライン関数を記述するための省略表現であり、動作を変更すべきではないが、この例では明らかにそうであるため、これは意味をなさない。

答えて

4

私はそれが実行のタイミングの問題だと思う - ラムダはもう少し時間がかかり、ファイルを読み終える前にプログラムを終了させるかもしれない。

ことは、これを試してみてください:

  • ReadFileUsingSupplierでtryブロック内の最初のステートメントとしてThread.sleep(1000);を追加し、ReadFileUsingLambdaを使用しているときの出力
  • はあなたのメインの終わりにThread.sleep(1000);が追加表示されませんし、あなたは確認するために、将来が完了する前に、あなたのメイン、あなたがいないの出口を呼び出すことができないと予想出力

が表示されます。

result.join(); 
+0

ありがとうございます。これはトリックでしたが、どのように私のプログラムがCompletableFutureから結果を返すまで終了しないようにするにはどうすればいいですか –

+2

@SulAga単に 'result.get()'または 'result.join()'を呼び出すことができます – assylias

+0

したがって、参加または取得はブロッキングコールですか?メインスレッドまたはCompletableFutureスレッドでブロックされていますか?これは問題です。つまりブロックします。 –

2

このように、いずれの場合も、メインスレッドが速すぎて終了しないようにするには、result.join()を実行する必要があります。

JVMがウォームアップしている間にlambdaと匿名のクロージャを使用するとペナルティが発生し、その後のパフォーマンスは同じようです。私はこの情報をanother SO threadに見つけました。これは、a performance study by Oracleをリンクしています。

サイドビューとして、奇妙なタイミングの問題を修正するためにThread.sleep()を使うのは良い考えではありません。あなたや他の人が再読み込みすると、原因を特定して適切な措置を適用すると、はるかに明確になります。

これにより、.join()もディッチすることができます。

関連する問題