2016-07-23 12 views
2

非同期タスクを作成し、CompletableFutureを返すメソッド(別のスレッドで同時に呼び出すことができる)があります。私が合格ラムダは非同期で実行されますJavaスコープの非同期ラムダをローカル変数に適用する方法

public CompletableFuture<Result> createTask(...) { 
    CompletableFuture<Result> result = ...; 
    final long startTime = System.currentTimeMillis(); 
    result.whenComplete((res, err) -> { 
     System.out.println(System.currentTimeMillis() - startTime); 
    } 
} 

と私は意志を書いた方法:私は、それは次のようにwhenComplete(...)でそれを連鎖してタスクを実行するのにかかる時間を測定したいですマルチスレッド化することもできます。このラムダは正確な時間を印刷することができますか?ラムダが別のスレッドによって非同期に実行されると、Javaはどのように可変スコープを処理するのですか?

+0

質問を再度読み、編集してください。文言はあまり明確ではない。 – michaelsnowden

答えて

4

ラムダが変数をキャプチャすると、その変数の値のコピーを取得するラムダと考えることができます。最終的な、または効果的な最終変数のみを取り込むことができるので、lambdaがそれらをコピーすることは安全です。それらの値は変更されないので、コピーが元の変数と同期しなくなる危険はありません。

Lambdaは匿名クラスで実装する必要はありませんが、概念的には匿名クラスの構文砂糖と考えることができます。あなたのwhenComplete呼び出しは同等です:事がある

long startTime = System.currentTimeMillis(); 

result.whenComplete(new BiConsumer<T, U>() { 
    @Override public void accept(T res, U err) { 
     System.out.println(System.currentTimeMillis() - startTime); 
    } 
}); 

、変数キャプチャは、ラムダと新しいものではありません。匿名クラスも変数を取り込み、ラムダが来る前にそれを行いました。何が起こるか、彼らは密かにキャプチャされた変数のコピーを隠す。これらの隠し値を格納する合成プライベートフィールドを取得します。一度この匿名BiConsumerはそれ自身の足で立ってインスタンス化され

long startTime = System.currentTimeMillis(); 

result.whenComplete(new BiConsumer<T, U>() { 
    private final long _startTime = startTime; 

    @Override public void accept(T res, U err) { 
     System.out.println(System.currentTimeMillis() - _startTime); 
    } 
}); 

注意:上記のコードは、実際に我々が明示的な合成フィールドを作れば、より多くのこのようなものです。 accept()の本文は、キャプチャされた変数ではなく、インスタンス変数を参照します。匿名オブジェクトは外部関数にも、作成されたスレッドにも結び付けられません。 accept()は、元のstartTime変数が死んで埋没してから長い場合でも、いつでもスレッドから呼び出すことができ、期待どおりに動作します。

関連する問題