この質問の鍵は、
複数のタスクを実行するためにスレッドを実際に再利用し、スレッドを終了せずにスレッドのプールを維持するつもりか [A] または
特定の時点で実行できる同時タスクの数を制御するための制限としてのみプールを使用するかどうか、および各実行後にスレッドが強制終了され、代わりに別のスレッドを作成する必要があるかどうか。[B]
[B] 未処理のジョブ リクエストの総数がシステムの制限を下回っている場合は、新しい Thread オブジェクトを返すことで非常に簡単に達成できます。明らかに、スレッド オブジェクトは、終了する前に共通リソース使用カウンターを減らす方法を知っている必要があります。この場合、スレッドのコレクションを維持する必要はなく、すべてのスレッドから共通の参照カウント オブジェクト (セマフォなど) への参照を維持するだけで済みます。
[A] ただし、特定のタスクの実行が終了しても終了せず、次のタスクが実行されるのを待つ Thread から継承されたクラスが必要です。このクラスが使用可能になると、適切なスレッド オブジェクト参照を呼び出し元に返すだけで、スレッドを使用済みまたはスレッド セーフでない方法でマークするマーカーを使用できます。
これを実現する簡単な方法の 1 つを次に示します。
ArrayList<MyThread> pool = new ArrayList<MyThread> (DEFAULT_POOL SIZE);
ArrayList<AtomicBoolean> used = new ArrayList<AtomicBoolean> (DEFAULT_POOL SIZE);
pool[i] を呼び出し元に返す場合は、使用中としてマークします。
used[i].set(true).
スレッドがプールに返されたときに、同じオブジェクトを使用されていないものとしてマークします (set(false))。同期された割り当て/割り当て解除メソッドからこれを行うことは明らかです。これらは同期されているため、プールされたスレッドを格納するために使用されるコレクションは、同期され、次にどのスレッドを発行するかを決定するために使用するアルゴリズムに応じて、任意の構造/コレクションを使用できます。
最適化として、プールされたスレッドの最初の要求でその場でプール (および個々のスレッド) を作成できます。これにより、使用可能になるまで初期化する必要がなくなります。ただし、スレッドセーフな方法で行う必要があります。詳細については説明しません。
質問 2 については、複数のプールを作成する場合を除き、プール クラスをシングルトンにすることをお勧めします。チェックを外すと危険です。また、非静的プール オブジェクトを使用している場合、インスタンス化されたプールの数を追跡する必要がなくなります。
示されているように、シナリオAを非常にうまく処理した既存のスレッドプールクラスを再利用することで、問題を解決できます:)