web-dev-qa-db-ja.com

CompletableFuture、supplyAsync()、およびthenApply()

何か確認する必要があります。次のコード:

CompletableFuture
    .supplyAsync(() -> {return doSomethingAndReturnA();})
    .thenApply(a -> convertToB(a));

次と同じです:

CompletableFuture
    .supplyAsync(() -> {
        A a = doSomethingAndReturnA();
        convertToB(a);
 });

右?

さらに、「thenApplyを使用する理由はありますか?」に関する次の2つの質問があります。

1)変換用の大きなコードを持っていますか?

または

2)ラムダブロックを他の場所で再利用する必要がありますか?

37
igr

同じものではありませんthenApplyが使用されない2番目の例では、convertToBへの呼び出しがメソッドdoSomethingAndReturnAと同じスレッドで実行されることが確実です。

ただし、最初の例では、thenApplyメソッドを使用すると、他のことが起こります。

まず、CompletableFutureを実行するdoSomethingAndReturnAが完了すると、呼び出し元のスレッドでthenApplyの呼び出しが行われます。 CompletableFuturesが完了していない場合、Functionに渡されたthenApplyは、doSomethingAndReturnAと同じスレッドで呼び出されます。

紛らわしい?よく この記事は役に立つかもしれません (リンクについて@SotiriosDelimanolisに感謝します)。

thenApplyがどのように機能するかを示す短い例を提供しました。

public class CompletableTest {
    public static void main(String... args) throws ExecutionException, InterruptedException {
        final CompletableFuture<Integer> future = CompletableFuture
                .supplyAsync(() -> doSomethingAndReturnA())
                .thenApply(a -> convertToB(a));

        future.get();
    }

    private static int convertToB(final String a) {
        System.out.println("convertToB: " + Thread.currentThread().getName());
        return Integer.parseInt(a);
    }

    private static String doSomethingAndReturnA() {
        System.out.println("doSomethingAndReturnA: " + Thread.currentThread().getName());
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        return "1";
    }
}

出力は次のとおりです。

doSomethingAndReturnA: ForkJoinPool.commonPool-worker-1
convertToB: ForkJoinPool.commonPool-worker-1

そのため、最初の操作が遅い(つまり、CompletableFutureがまだ完了していない)場合、両方の呼び出しが同じスレッドで発生します。ただし、doSomethingAndReturnAからThread.sleep- callを削除する場合、出力は(おそらく)次のようになります。

doSomethingAndReturnA: ForkJoinPool.commonPool-worker-1
convertToB: main

convertToB呼び出しはmainスレッド内にあることに注意してください。

56
wassgren

thenApply()はコールバック関数であり、supplyAsync()が値を返すときに実行されます。

コードスニペット2では、doSomethingAndReturnA()を呼び出したスレッドは、関数が実行されてデータが返されるまで待機します。

しかし、いくつかの例外的なケース(Webサービスの呼び出しや応答の待機など)では、スレッドは応答を取得するためにlong時間待機する必要があり、システムの計算リソースを大量に消費します(応答を待機するだけです) 。

それを避けるために、CompletableFutureにはcallback機能が付属しています。この機能では、doSomethingAndReturnA()が呼び出されると、別のスレッドがdoSomethingAndReturnA()の実行を処理します。そして、メインの呼び出し元スレッドは、応答が戻るのを待たずに他の操作を続けます。

doSomethingAndReturnAの応答が利用可能になると、コールバックメソッドが呼び出されます(つまり、thenApply()

2
user3016425