JDK 11の新しいHTTPクライアントAPI、特にリクエストを実行する非同期の方法を試しています。しかし、私が理解できるかどうかわからないことがあります(実装の側面のようなものです)。 documentation には、次のように書かれています。
返された
CompletableFuture
インスタンスの非同期タスクと依存アクションは、実用的な場合、クライアントのExecutor
によって提供されるスレッドで実行されます。
これを理解しているので、HttpClient
オブジェクトを作成するときにカスタムエグゼキュータを設定すると、次のようになります。
ExecutorService executor = Executors.newFixedThreadPool(3);
HttpClient httpClient = HttpClient.newBuilder()
.executor(executor) // custom executor
.build();
次に、リクエストを非同期で送信し、返されたCompletableFuture
に依存アクションを追加すると、依存アクションは指定されたエグゼキュータで実行されるはずです。
httpClient.sendAsync(request, BodyHandlers.ofString())
.thenAccept(response -> {
System.out.println("Thread is: " + Thread.currentThread().getName());
// do something when the response is received
});
ただし、上記の依存アクション(thenAccept
のコンシューマー)では、Thread is: ForkJoinPool.commonPool-worker-5
を出力するため、それを実行するスレッドはカスタムエグゼキューターではなく共通プールからのものであることがわかります。
これは実装のバグですか?または私が欠けている何か? 「インスタンスはクライアントのエグゼキュータによって提供されたスレッドで実行されます実用的な場合」と書かれているのに気づきましたが、これは適用されない場合ですか?
thenAcceptAsync
も試しましたが、同じ結果であることに注意してください。
更新された ドキュメント (最初にリンクしたものは古いようです)を見つけました。ここで、この実装動作を説明しています。
一般に、非同期タスクは、操作を呼び出すスレッドのいずれかで実行されます。 送信 HTTPリクエスト、またはクライアントの エグゼキュータ によって提供されるスレッドによって。 エグゼキュータを明示的に指定しない、返されたCompletionStagesまたはCompletableFuturesによってトリガーされる依存タスクは、
CompletableFuture
、または依存タスクが登録される前に操作が完了した場合は呼び出しスレッド。
また、CompletableFuture
のデフォルトのエグゼキュータは共通プールです。
また、この動作を導入する バグID も見つかりました。ここでは、API開発者が完全に説明しています。
2)共通プールで実行される依存タスク依存タスクのデフォルトの実行が更新され、CompletableFutureのdefaultExecutorと同じエグゼキューターで実行されるようになりました。これは、すでにCFを使用している開発者にとってはなじみがあり、HTTPクライアントがタスクを実行するためにスレッドが不足する可能性を減らします。これは単なるデフォルトの動作であり、HTTPクライアントとCompletableFutureの両方で、必要に応じてよりきめ細かい制御が可能です。
ショートバージョン:実装の詳細を特定したと思います。「wherepractical」は、提供されたexecutor
が保証されないことを意味します。利用される。
詳細に:
ここ からJDK11ソースをダウンロードしました。 (この記事の執筆時点ではjdk11-f729ca27cf9a
)。
src/Java.net.http/share/classes/jdk/internal/net/http/HttpClientImpl.Java
には、次のクラスがあります。
/**
* A DelegatingExecutor is an executor that delegates tasks to
* a wrapped executor when it detects that the current thread
* is the SelectorManager thread. If the current thread is not
* the selector manager thread the given task is executed inline.
*/
final static class DelegatingExecutor implements Executor {
このクラスは、executor
がtrueの場合はisInSelectorThread
を使用し、それ以外の場合はタスクをインラインで実行します。これは要約すると次のようになります。
boolean isSelectorThread() {
return Thread.currentThread() == selmgr;
}
ここで、selmgr
はSelectorManager
です。 編集:このクラスはHttpClientImpl.Java
にも含まれています:
// Main loop for this client's selector
private final static class SelectorManager extends Thread {
結論:実用的は実装に依存し、提供されたexecutor
が使用される保証がないことを意味すると推測しています。
注:これは、ビルダーがexecutor
を提供しないデフォルトのエグゼキューターとは異なります。その場合、コードは明らかに新しいキャッシュスレッドプールを作成します。別の言い方をすれば、ビルダーがexecutor
を提供する場合、SelectorManager
のIDチェックが行われます。