- PR -

スレッドプールのカスタマイズ

1
投稿者投稿内容
じゃヴぁ
会議室デビュー日: 2006/01/05
投稿数: 2
投稿日時: 2006-01-05 00:31
初めての書き込みです。よろしくお願いします。

JDK5からjava.util.concurrentパッケージが導入され,
スレッド制御周りが便利になったと聞き,
使ってみたのですが,思い通りには動いてくれません。

[実現したいこと]
@スレッドの最大数を制限したい。
A必要最低限なスレッドしか生成しない。一度作ったスレッドはプールする。空いているスレッドがあれば再利用する。
Bスレッドが最大数に達して実行できない処理は待ち行列に入り,スレッドが空き次第実行する。この待ち行列には,無限に処理を格納できる。

[試み1]
Executors#newFixedThreadPool(又はnewScheduledThreadPool)のExecutorServiceだと,
Aが実現できません。
具体例(スレッド数は2以上を指定)
処理1の実行を依頼し,スレッドAが生成され,処理1が実行される。
処理1の実行が完了してスレッドAがアイドル状態になる。
その後に,
新たな処理2の実行を依頼すると,スレッドBが生成され,処理2が実行される。
ここで,処理2の処理は,新規にスレッドを生成するのではなく,
アイドル状態のスレッドAを使ってもらいたいのです。
Aの項目は実現できます。
@:○ A:× B:○

[試み2]
Executors#newCachedThreadPoolで作成したExecutorServiceだと,
@の最大スレッド数の制御が実現できません。
そのため,平行した複数の処理があると、その数だけスレッドが存在します。
@:× A:○ B:?

[試み3]
Executors#newFixedThreadPool,#newCachedThreadPoolはThreadPoolExecutorの
コンストラクタ引数を変えることで,挙動を操作しているようなので,
引数を変えていろいろと試してみたんですが,@ABを満たせていません。

[ご質問]
@ABを満たすにはどうすればよいのでしょうか?ThreadPoolExecutorのコンストラクタ引数を操作することで実現できるものでしょうか。
java.util.concurrentパッケージのクラスでは無理なんでしょうか?
自作Executorを作るしかないのでしょうか?
ご教授お願いします。

#最終目標は,時間をトリガーにスレッドを立ち上げたいので
#@ABを満たしたScheduledThreadPoolExecutorです。

[スレッドプールの勉強をさせていただいたWebページ]
・http://www.javaworld.jp/technology_and_programming/-/23241.html
・http://www.javainthebox.net/laboratory/J2SE1.5/MiscAPI/ConcurrencyUtils/ConcurrencyUtils1.html
シュン
ぬし
会議室デビュー日: 2004/01/06
投稿数: 328
お住まい・勤務地: 東京都
投稿日時: 2006-01-05 01:57
ThreadPoolExecutor#execute()の実装を読むと、corePoolSize回までの呼び出しでは、
execute()の呼び出しタイミングでの空きスレッドのあるなしをチェックせずに、スレッド
数を拡張するようです。

必要最低限のスレッド数=corePoolSizeと考えれば@〜Bを満たすように動作していること
になりますよね?厳密にはあなたの望む動作と異なっていますが、このような動作で問題が
あるとは考えにくいのですが…何が問題になるのでしょうか?
じゃヴぁ
会議室デビュー日: 2006/01/05
投稿数: 2
投稿日時: 2006-01-07 15:24
シュンさん、回答いただきありがとうございます。

微妙な差なんです。corePoolSizeになるまで再利用しないでスレッド生成するのがもったいないなと感じてしまっただけなんです。

[具体例]
平常時は、処理要求が並列にくることはほとんどありません。あっても並列する要求は2,3になります。

混雑時は、大量の処理要求が並列にきます。その場合にスレッド増加によるスループット低下を避ける・安定稼動などのために、スレッド数の上限を設けておきます。
平常と混雑のバランスが、混雑時が年に2時間だけで、他は平常時であるとします。平常時が三ヶ月続き混雑時が発生してない場合に、corePoolSize分のアイドル状態スレッドがたまってしまうのが無駄に感じました。




ThreadPoolExecutorの引数をいろいろといじくり試してみたんで、どなたかの参考になるかもしれないので掲載します。

[試み4]
new ThreadPoolExecutor(0, maxSize, Long.MAX_VALUE, TimeUnit.SECONDS, new SynchronousQueue<Runnable>())
条件Bの「無限に処理を格納できる」だけ実現できません。
@:○ A:○ B:×

[試み5]
new ThreadPoolExecutor(0, maxSize, Long.MAX_VALUE, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>())
処理がキューに入るだけで一切実行されません。よって、まったく使い物になりません。
@:× A:× B:×


どれも紙一重でダメなので残念です。
シュン
ぬし
会議室デビュー日: 2004/01/06
投稿数: 328
お住まい・勤務地: 東京都
投稿日時: 2006-01-16 09:51
>微妙な差なんです。corePoolSizeになるまで再利用しないでスレッド生成するのがもっ>たいないなと感じてしまっただけなんです。

主観の問題ならば、気にしないのが一番良いと思いますよ。
「生成されただけで使われないスレッド」が消費するリソースがいったい何なのかを
考えてみると、あまり気にしなくて良いことが分かると思います。
1

スキルアップ/キャリアアップ(JOB@IT)