作成できるスレッドの数に制限があるキャッシュされたスレッド プールを作成することは不可能であるようです。
Executors.newCachedThreadPool
標準 Java ライブラリでstatic がどのように実装されているかを示します。
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
そこで、そのテンプレートを使用して、固定サイズのキャッシュされたスレッド プールを作成します。
new ThreadPoolExecutor(0, 3, 60L, TimeUnit.SECONDS, new SynchronusQueue<Runable>());
これを使用して 3 つのタスクを送信すると、すべて正常に動作します。それ以上のタスクを送信すると、実行例外が拒否されます。
これを試してみましょう:
new ThreadPoolExecutor(0, 3, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runable>());
すべてのスレッドが順番に実行されます。つまり、スレッド プールはタスクを処理するために複数のスレッドを作成することはありません。
これは の execute メソッドのバグですかThreadPoolExecutor
? それとも意図的なものでしょうか? あるいは他の方法があるのでしょうか?
編集: キャッシュされたスレッド プール (要求に応じてスレッドを作成し、タイムアウト後にスレッドを強制終了する) とまったく同じものが必要ですが、作成できるスレッドの数に制限があり、スレッド制限に達した後も追加のタスクをキューに入れ続ける機能が必要です。sjlee の回答によると、これは不可能です。そのexecute()
メソッドを見ると、確かに不可能です。のようにサブクラス化してオーバーライドするThreadPoolExecutor
必要がありますが、そのメソッドで行われていることは完全なハックです。ThreadPoolExecutor
execute()
SwingWorker
SwingWorker
execute()
ベストアンサー1
にはThreadPoolExecutor
次のいくつかの重要な動作があり、問題はこれらの動作によって説明できます。
タスクが提出されると、
- スレッド プールがコア サイズに達していない場合は、新しいスレッドが作成されます。
- コア サイズに達し、アイドル スレッドがない場合、タスクはキューに入れられます。
- コア サイズに達し、アイドル スレッドがなくなり、キューがいっぱいになると、新しいスレッドが作成されます (最大サイズに達するまで)。
- 最大サイズに達し、アイドル スレッドがなくなり、キューがいっぱいになると、拒否ポリシーが有効になります。
最初の例では、SynchronousQueue
サイズは基本的に 0 であることに注意してください。したがって、最大サイズ (3) に達した瞬間に、拒否ポリシーが有効になります (#4)。
2 番目の例では、選択されたキューはLinkedBlockingQueue
サイズが無制限のキューです。そのため、動作 #2 に陥ってしまいます。
キャッシュ型や固定型の動作はほぼ完全に決まっているため、実際にあまりいじることはできません。
制限された動的なスレッドプールが必要な場合は、正のコアサイズと最大サイズを有限サイズのキューと組み合わせて使用する必要があります。たとえば、
new ThreadPoolExecutor(10, // core size
50, // max size
10*60, // idle timeout
TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(20)); // queue with a size
補遺: これはかなり古い回答ですが、JDK はコア サイズが 0 になると動作が変わったようです。JDK 1.6 以降、コア サイズが 0 でプールにスレッドがない場合、ThreadPoolExecutor はスレッドを追加してそのタスクを実行します。したがって、コア サイズが 0 の場合は上記のルールの例外となります。ありがとうございます。スティーブのためにもたらすそれは私の注意を引くでしょう。