過去 3 か月間、さまざまなマルチスレッド フレームワークについて調査した結果、疑問に対する答えが見つかりました。
ExecutorService
限られた制御でシンプルで使いやすいです。あなたはそれを使用することができます
- 待機なしで独立した並列タスクを開始するには
- すべてのタスクの完了を待ちます
Callable/Runnable
タスクの数が少なく、無制限のキューにタスクが山積みされてもメモリが山積みされず、システムのパフォーマンスが低下しない場合は、これを好みます。
の低レベルの詳細を隠しますThreadPoolExecutor
。Bounded Queue, Rejection Handler
のように、他のパラメーター (パフォーマンスを微調整するためなど) を操作することはできませんThreadPoolExectuor
。
ThreadPoolExecutor
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime,
TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory,
RejectedExecutionHandler handler)
それはあなたにより多くの制御を提供します。最小スレッドと最大スレッドの設定とは別に、キュー サイズを設定して、makeBlockingQueue
を制限することができます。
以下の機能が必要な場合は、独自のスレッド ファクトリを考え出すことができます。
- よりわかりやすいスレッド名を設定するには
- スレッドデーモンのステータスを設定するには
- スレッドの優先度を設定するには
保留中の Runnable/Callable タスクの数によってアプリケーションが制約されている場合は、最大容量を設定して制限付きキューを使用します。キューが最大容量に達すると、RejectionHandler を定義できます。Java には、4 種類の拒否ハンドラポリシーが用意されています。
デフォルトThreadPoolExecutor.AbortPolicy
では、ハンドラーは拒否時にランタイム RejectedExecutionException をスローします。
ではThreadPoolExecutor.CallerRunsPolicy
、execute を呼び出すスレッド自体がタスクを実行します。これにより、新しいタスクが送信される速度を遅くする単純なフィードバック制御メカニズムが提供されます。
ではThreadPoolExecutor.DiscardPolicy
、実行できないタスクは単にドロップされます。
ではThreadPoolExecutor.DiscardOldestPolicy
、executor がシャットダウンされていない場合、ワーク キューの先頭にあるタスクが削除され、実行が再試行されます (再度失敗する可能性があり、これが繰り返される可能性があります)。
カウントダウンラッチ
CountDownLatch
: このフレームワークにより、Java スレッドは、他の一連のスレッドがタスクを完了するまで待機できます。
使用例:
最大並列処理の実現: 最大並列処理を実現するために、同時に多数のスレッドを開始したい場合があります。
他のコード ブロックの実行を開始する前に、N 個のスレッドが完了するのを待ちます
デッドロック検出。
詳しくはこちらの記事にまとめています
ForkJoinPool
はForkJoinPool
Java ExecutorService に似ていますが、1 つの違いがあります。これForkJoinPool
により、タスクが作業をより小さなタスクに分割しやすくなり、それらのタスクは ForkJoinPool にも送信されます。空きワーカー スレッドがビジー ワーカー スレッド キューからタスクを盗むと、ForkJoinPool でタスク盗用が発生します。
public ForkJoinPool(int parallelism,
ForkJoinPool.ForkJoinWorkerThreadFactory factory,
Thread.UncaughtExceptionHandler handler,
boolean asyncMode)
Creates a ForkJoinPool with the given parameters.
パラメーター:
並列処理- 並列処理レベル。デフォルト値には、 を使用しますRuntime.availableProcessors()
。
factory - 新しいスレッドを作成するためのファクトリ。デフォルト値には、defaultForkJoinWorkerThreadFactory を使用します。
handler - 回復不能なエラーが原因で終了する内部ワーカー スレッドのハンドラー
asyncMode - true の場合、決して結合されないフォークされたタスクのローカル先入れ先出しスケジューリング モードを確立します。
メインクエリについて:
ExecutorService.invokeAll()
またはCountDownLatch
フレームワーク またはを使用できますForkJoinPool
。これらのフレームワークはすべて、高レベルから低レベルまでのタスクの実行を制御するために、さまざまな粒度を相互に補完します。
編集:
関連する SE の質問をご覧ください。
ExecutorService を使用する利点は何ですか?
Java の Fork/Join と ExecutorService - いつどちらを使用するか?