次のコードがあるとします:
CompletableFuture<Integer> future
= CompletableFuture.supplyAsync( () -> 0);
thenApply
ケース:
future.thenApply( x -> x + 1 )
.thenApply( x -> x + 1 )
.thenAccept( x -> System.out.println(x));
ここで、出力は2になります。thenApplyAsync
の場合:
future.thenApplyAsync( x -> x + 1 ) // first step
.thenApplyAsync( x -> x + 1 ) // second step
.thenAccept( x -> System.out.println(x)); // third step
これを読みます ブログ 各thenApplyAsync
は別々のスレッドで実行され、「同時に」(つまり、thenApplyAsyncs
の前にthenApplyAsyncs
が開始されることを意味します] _ finish)、そうであれば、最初のステップが終了していない場合の2番目のステップの入力引数値は何ですか?
2番目のステップで行われなかった場合、最初のステップの結果はどこに行きますか? 3番目のステップはどのステップの結果を取りますか?
2番目のステップが最初のステップの結果を待つ必要がある場合、Async
のポイントは何ですか?
ここでx-> x + 1はポイントを示すためだけのもので、非常に長い計算の場合に知りたいことです。
違いは、コードの実行を担当するExecutor
に関係しています。 CompletableFuture
の各演算子には、通常3つのバージョンがあります。
thenApply(fn)
-fn
によって定義されたスレッドでCompleteableFuture
を実行します。そのため、これが実行される場所を一般に知ることができません。結果がすでに利用可能な場合、すぐに実行される場合があります。thenApplyAsync(fn)
-状況に関係なく、環境定義のエグゼキューターでfn
を実行します。 CompletableFuture
の場合、これは通常ForkJoinPool.commonPool()
になります。thenApplyAsync(fn,exec)
-fn
でexec
を実行します。最終的に結果は同じですが、スケジューリングの動作は方法の選択に依存します。
名前thenApply
とthenApplyAsync
は絶対に恐ろしく、紛らわしいことを指摘しなければなりません。 thenApplyAsync
には、これらのメソッドのコントラクトからのthenApply
よりも非同期なものはありません。
違いは、関数が実行されるスレッドと関係があります。 thenApply
に提供される関数 どのスレッドでも実行可能
complete
を呼び出しますthenApply
を呼び出します一方、thenApplyAsync
はデフォルトのExecutor
(別名スレッドプール)を使用するか、指定されたExecutor
を使用します。
これらの関数の非同期部分は、非同期操作が最終的にcomplete
またはcompleteExceptionally
を呼び出すという事実に関係しています。このアイデアは、マルチスレッドとは関係のないJavascriptから生まれました。
これは、ドキュメントがCompletableFuture's
thenApplyAsync
について述べていることです:
このステージが正常に完了すると、このステージのデフォルトの非同期実行機能を使用して、このステージの結果が提供された関数の引数として実行される新しいCompletionStageを返します。
したがって、thenApplyAsync
は、前のthenApplyAsync's
結果を待つ必要があります。
あなたの場合、最初に同期作業を行い、次に非同期作業を行います。したがって、同期作業が終了した後にのみ開始されるため、2番目のものが非同期であることは重要ではありません。
切り替えましょう。場合によっては「非同期結果:2」が最初に印刷され、場合によっては「同期結果:2」が最初に印刷されます。ここでは、呼び出し1と呼び出し2の両方が非同期に実行でき、別々のスレッドで1を呼び出し、他のスレッド(メインスレッドである可能性がある)で2を呼び出すことができるため、違いが生じます。
CompletableFuture<Integer> future
= CompletableFuture.supplyAsync(() -> 0);
future.thenApplyAsync(x -> x + 1) // call 1
.thenApplyAsync(x -> x + 1)
.thenAccept(x -> System.out.println("async result: " + x));
future.thenApply(x -> x + 1) // call 2
.thenApply(x -> x + 1)
.thenAccept(x -> System.out.println("sync result:" + x));
2番目のステップ(つまり、計算)は常に最初のステップの後に実行されます。
2番目のステップが最初のステップの結果を待つ必要がある場合、非同期のポイントは何ですか?
この場合、非同期とは、メソッドが迅速に戻り、計算が別のスレッドで実行されることが保証されることを意味します。
thenApply
(非同期なし)を呼び出す場合、そのような保証はありません。この場合、CompletableFutureがメソッドが呼び出されるまでに既に完了している場合、thenApply
を呼び出す同じスレッドで同期的に実行できます。ただし、計算は、未来を完了するスレッドまたは同じCompletableFuture
でメソッドを呼び出す他のスレッドによって非同期に実行される場合もあります。この回答: https://stackoverflow.com/a/46062939/1235217 thenApplyが何を保証し、何を保証しないかを詳細に説明しました。
それで、いつthenApply
とthenApplyAsync
を使うべきですか?私は次の経験則を使用します。