通常、チュートリアルでは説明されていませんが、非常に重要なこと:
Runnables to be executed on an ExecutorService should not block
. これは、ブロックするたびに作業スレッドがオフになり、ExecutorService の作業スレッドの数が制限されている場合はデッドロック (スレッド スターベーション) に陥るリスクがあり、ExecutorService の作業スレッドの数が無制限の場合は、メモリが不足しています。タスクでのブロック操作は ExecutorService のすべての利点を単純に破壊するため、ブロック操作は通常のスレッドでのみ使用してください。
FutureTask.get()
ブロック操作であるため、ExecutorService タスクからではなく、通常のスレッドで使用できます。つまり、ビルディングブロックとして機能することはできず、実行結果をマスタースレッドに配信するだけです。
タスクから実行を構築するための正しいアプローチは、次のタスクのすべての入力データの準備が整ったときに次のタスクを開始することです。これにより、タスクは入力データの待機をブロックする必要がなくなります。したがって、中間結果を保存し、すべての引数が到着したときに新しいタスクを開始する一種のゲートが必要です。したがって、タスクは他のタスクを明示的に開始する必要はありません。したがって、引数の入力ソケットとそれらを計算する Runnable で構成されるゲートは、ExcutorServices での計算の適切なビルディング ブロックと見なすことができます。
このアプローチは、データフローまたはワークフローと呼ばれます (ゲートを動的に作成できない場合)。
Akka のようなアクター フレームワークはこのアプローチを使用しますが、アクターが単一の入力ソケットを持つゲートであるという点で制限があります。
https://github.com/rfqu/df4jで公開されている真のデータフロー ライブラリを作成しました。