エグゼキュータサービスを使用して作成された3つのスレッドがあり、t2がt1の後に実行を開始し、t3がt2の後に実行を開始するようにしたいとします。スレッドプールの場合にこの種のシナリオを実現する方法は?
thread.start()を使用して作成する通常のスレッドがある場合。join()メソッドを使用して待つこともできます。しかし、上記のシナリオをどのように処理するのでしょうか?
エグゼキュータサービスを使用して作成された3つのスレッドがあり、t2がt1の後に実行を開始し、t3がt2の後に実行を開始するようにしたいとします。スレッドプールの場合にこの種のシナリオを実現する方法は?
thread.start()を使用して作成する通常のスレッドがある場合。join()メソッドを使用して待つこともできます。しかし、上記のシナリオをどのように処理するのでしょうか?
ExecutorServiceに送信されるジョブは、相互に独立している必要があります。セマフォ、CountDownLatchesなどを待機して依存関係を確立しようとすると、使用可能なすべてのワーカースレッドが、送信されたジョブを待機しているが、現在のジョブの背後にあるジョブを実行すると、サービス全体がブロックされるリスクがあります。列。可能なブロックジョブよりも多くのワーカーがいることを確認する必要があります。ほとんどの場合、複数のExecutorServiceを使用して、依存グループの各ジョブを異なるサービスに送信することをお勧めします。
スレッドの概念とスレッドで実行される内容を混同しています。スレッドプールでスレッドがいつ「開始」されるかは問題ではありませんが、処理の実行がいつ開始または継続されるかは問題ではありません。したがって、より適切なステートメントは、3つのCallables
orRunnables
があり、続行する前に他の 2 つを待つために 1 つが必要であるということです。これはCountDownLatchを使用して行われます。カウントが 2 の共有ラッチを作成します。そのうちの 2つはラッチでcountDown()Callables
を呼び出し、待機する必要があるものはawait()を呼び出します(おそらくタイムアウト付き)。
いくつかのオプション:
これが対処しなければならない唯一のシナリオ (t1->t2->t3) である場合は、スレッド プールを使用しないでください。3 つのタスクを順番に実行します。
スレッド間通知メカニズム (BlockingQueue、CountDownLatch など) を使用します。これには、タスクが、選択した同期インストゥルメントへの共有参照を保持する必要があります。
依存シーケンスを新しい実行可能/呼び出し可能でラップして、単一のタスクとして送信します。このアプローチは単純ですが、非線形の依存関係トポロジーを正しく処理できません。
別のタスクに依存するすべてのタスクは、実行のために他のタスクを送信し、その完了を待機する必要があります。これは、依存関係のあるスレッド プールの一般的なアプローチですが、デッドロックの可能性を回避するために慎重に調整する必要があります (実行中のタスクは、実行できるスレッドがないタスクを待機する場合があります。簡単な解決策については、私の回答を参照してください)。
スレッド t1、t2、および t3 は呼び出し可能なインターフェイスを実装でき、call メソッドから何らかの値を返すことができます。戻り値に基づいて、t1 が戻った後、t2 を開始し、t3 についても同様に開始できます。
「Callable」がその答えです