2

Java には、Fork/Join プール、Executor Service、CountDownLatchという 3 つの異なるマルチスレッド技術があります。

Fork/Join プール( http://www.javacodegeeks.com/2011/02/java-forkjoin-parallel-programming.html )

Fork/Join フレームワークは、分割統治アルゴリズムを簡単に並列化できるように設計されています。このタイプのアルゴリズムは、同じタイプの 2 つ以上のサブ問題に分割できる問題に最適です。再帰を使用して、問題を単純なタスクに分解し、それらが直接解決できるほど単純になるまで続けます。次に、サブ問題の解決策を組み合わせて、元の問題の解決策を提供します。

ExecutorServiceは、Executor クラスを拡張し、非同期実行を表すインターフェースです。非同期タスクの終了を管理し、進行状況を検出するメカニズムを提供します。

invokeAll() : 指定されたタスクを実行し、すべてが完了するとステータスと結果を保持する Future のリストを返します。Future.isDone() は、返されたリストの各要素に対して true です。

CountDownLatch :( http://examples.javacodegeeks.com/core-java/util/concurrent/countdownlatch-concurrent/java-util-concurrent-countdownlatch-example/ )

CountDownLatch は同期で使用され、他のスレッドで実行されている一連の操作が完了するまで、1 つ以上のスレッドを待機させることができます。

私の仮定:

これらのどちらの方法でも、最終結果はすべてのタスク/スレッドの完了後にのみわかります。

これらの 3 つの代替案は、相互に補完的または補足的ですか?

4

1 に答える 1

13

過去 3 か月間、さまざまなマルチスレッド フレームワークについて調査した結果、疑問に対する答えが見つかりました。

ExecutorService

限られた制御でシンプルで使いやすいです。あなたはそれを使用することができます

  1. 待機なしで独立した並列タスクを開始するには
  2. すべてのタスクの完了を待ちます

Callable/Runnableタスクの数が少なく、無制限のキューにタスクが山積みされてもメモリが山積みされず、システムのパフォーマンスが低下しない場合は、これを好みます。

の低レベルの詳細を隠しますThreadPoolExecutorBounded Queue, Rejection Handlerのように、他のパラメーター (パフォーマンスを微調整するためなど) を操作することはできませんThreadPoolExectuor

ThreadPoolExecutor

ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, 
TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory,
RejectedExecutionHandler handler)

それはあなたにより多くの制御を提供します。最小スレッドと最大スレッドの設定とは別に、キュー サイズを設定して、makeBlockingQueueを制限することができます。

以下の機能が必要な場合は、独自のスレッド ファクトリを考え出すことができます。

  1. よりわかりやすいスレッド名を設定するには
  2. スレッドデーモンのステータスを設定するには
  3. スレッドの優先度を設定するには

保留中の Runnable/Callable タスクの数によってアプリケーションが制約されている場合は、最大容量を設定して制限付きキューを使用します。キューが最大容量に達すると、RejectionHandler を定義できます。Java には、4 種類の拒否ハンドラポリシーが用意されています。

  1. デフォルトThreadPoolExecutor.AbortPolicyでは、ハンドラーは拒否時にランタイム RejectedExecutionException をスローします。

  2. ではThreadPoolExecutor.CallerRunsPolicy、execute を呼び出すスレッド自体がタスクを実行します。これにより、新しいタスクが送信される速度を遅くする単純なフィードバック制御メカニズムが提供されます。

  3. ではThreadPoolExecutor.DiscardPolicy、実行できないタスクは単にドロップされます。

  4. ではThreadPoolExecutor.DiscardOldestPolicy、executor がシャットダウンされていない場合、ワーク キューの先頭にあるタスクが削除され、実行が再試行されます (再度失敗する可能性があり、これが繰り返される可能性があります)。

カウントダウンラッチ

CountDownLatch: このフレームワークにより、Java スレッドは、他の一連のスレッドがタスクを完了するまで待機できます。

使用例:

  1. 最大並列処理の実現: 最大並列処理を実現するために、同時に多数のスレッドを開始したい場合があります。

  2. 他のコード ブロックの実行を開始する前に、N 個のスレッドが完了するのを待ちます

  3. デッドロック検出。

詳しくはこちらの記事にまとめています

ForkJoinPool

ForkJoinPoolJava 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 - いつどちらを使用するか?

于 2015-11-09T05:01:33.030 に答える