スレッドプールの利点:
- リソースのオーバーヘッドを削減:各タスクは、到着時に再作成および破棄する必要はありません。
- 統一されたスレッドのチューニング、監視:管理性を向上させます
- 応答時間を改善するタスク:スレッドの作成を待つ必要はありません
スレッドプールの様々なパラメータが作成されます。
- corePoolSize:スレッドのコア数。コアは、スレッドの数より少ない場合、優先順位は、完全なコアの数(スペアカーネルスレッドがあっても)スレッドを作成することもあります
- maximumPoolSize:スレッドの最大数。フルワークキューは、新しいタスクを実行する新しいスレッドを作成した場合
- keepAliveTimeが:生存。非コアスレッドは最大時間を割くことができます
- ワークキュー:タスクキューを遮断します。新しいタスクを提出し、スレッドのコア数は最大使用されている場合は、新しいタスクがタスクキューに参加することになります
スレッドプールの作成プロセス:
- タスクを送信すると、最初のスレッドのコア数を決定作成されているかどうかをされていない場合、最初のスレッドの完全なコア数を作成し、そうでない場合は、次の段階に入ります
- 全て占有されているスレッドのコアの数かどうかを決定し、そうでない場合は実行するコア糸、逆に次の段階に
- 作業キューがいっぱいになっているかどうかを判断し、フルキュー待ちに参加していない場合は、逆に次のステージへ
- そう、新しいスレッドがタスクを実行するために作成されている場合、スレッドの現在の数がMaxThread未満であるかを決定、;逆ポリシーにRejectPolicyHandlerは、対応する呼び出しを実行します
スレッドプールを作成します。
私たちは、ThreadPoolExecutorでスレッドプールを作成することができます
ThreadPoolExecutor(
int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler)
1)corePoolSizeは:他のコアがアイドル状態のスレッドが新しいタスクを実行することができている場合でも、あなたは)(タスクを送信すると、スレッドプールは、それはもはや作成され、corePoolSizeスレッドが作成されるまで、タスクを実行するために、新しいスレッドを作成しません。あなたが追加作成したい場合は、バックパラメータに依存します。スレッドが呼び出した場合はprestartAllCoreThreads()
、スレッドプールを作成して起動する方法は、すべてのコアスレッドを進めます
2)maximumPoolSize:スレッドプール内のスレッドの最大数を生成することができます。キューがいっぱいになると、スレッドの最大数よりも少ないが作成されているスレッドの数と、スレッド・プールには、タスクを実行するために、新しいスレッドを再作成します。アンバウンド形式のキューは、このパラメータが有効でない場合
3)keepAliveTimeがアイドルワーカースレッドプールの後、時間を生きて維持します。各スレッドの実行時間が短い場合は、この値が大きく増加スレッドの使用率を転送することができます
4)単位:時間の単位
5)ワークキュー:実行待ちキューをブロックするタスクを保存するために、あなたは以下のブロッキングキューを選択することができます。
* ArrayBlockingQueue: 是一个基于数组结构的有界阻塞队列,此队列按FIFO原则队元素进行排序
* LinkedBlockingQueue: 一个基于链表结构的阻塞,此队列按FIFO排序元素,吞吐量通常要高于ArrayBlockingQueue。静态工厂方法Executors.newFixedThreadPool()使用了这个队列。
* SynchronousQueue: 一个不存储元素的队列。每个插入操作要必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQueue,静态工厂方法Executors.newCachedThreadPool使用了这个队列
* PriorityQueue: 一个具有优先级的无限阻塞队列
6)ハンドラ:RejectPolicyのデフォルト、4があります:
* AbortPolicy、直接スロー例外
* DiscardPolicy、処理をあきらめ、タスクを破棄
* CallerRunsPolicyは、のみ、呼び出し元のスレッドがタスクを実行する
* DiscardOldestPolicyは、キューキュー要素の頭を破棄
ミッション
それぞれ、スレッドプールにタスクを提出する)((実行)し、送信するには、2つの方法がありますスレッドプールのタスクを提出してください:
- 実行:戻り値を実行しなかった後、タスクが正常にスレッドプール実行されたかどうかを判断することができません
- 提出:Futureオブジェクトで、返しますタイプの未来のオブジェクトを提出した後、実行が成功したかどうかを判断することができます。タスクが完了するまでメソッドはブロックを現在のスレッドを取得することができ、取得(タイムアウト、単位)メソッドは、現在のスレッドが戻った後、いくつかの時間のためにブロックすることができます
閉じるスレッド
そこにそれぞれ、スレッドプールを閉鎖するための2つの方法があり、shutdown()
かつshutdownNow()
共通シング:
すべてのスレッドは、スレッドプールを横断した後、1呼び出しスレッドずつinterrupt()
スレッドを中断するための方法、私は中断したスレッド終了されない場合がありに応答することはできません。
違い:
- スレッドプールのshutdownNowの最初の状態が停止し、その後、すべてのスレッドが実行されて停止したり、タスクを中断しようとするように設定し、実行を待っているタスクのリストを返します
- スレッドプールのシャットダウンだけ状態がSHUTDOWN状態に設定され、その後、すべてのスレッドミッションを中断されていません
シャットダウン方法のいずれかが呼び出されると、isShutdown()メソッドがtrueを返します。すべてのタスクを閉じたときに、isTerminated()を呼び出してtrueを返します。
具体的にコールするshutdown()
か、shutdownNow()
(通常はサービスによって呼び出す判断する必要がありますshutdown()
)。タスクが実行されるように、必ずしもではない場合は、使用することができますshutdownNow()
合理的な配分
- CPU集中型のタスク、IO集約型のタスク、ハイブリッドミッション:タスクの自然
- 優先度のタスク:高、中、低
- タスクの実行時間:ロング、セミロング、ショート
- 依存タスク:データベース接続など他のシステムリソースに依存するかどうか
どのように選択するには:
- CPU集約的なタスクは、CPUの動作を使用するように長い時間がかかるスレッドの数は、好ましくは構成されている:N のCPU + 1。
- IO集約型のタスクは、できるだけ多くのスレッドを設定し、CPUによって占領されていない:2 * N CPU
- タスクがハイブリッドである場合は、CPU集約型のタスクとIO集約型のタスクに分割してみてください
- なぜならSQLデータベースを提出するスレッドを待つ必要の依存タスクデータベース接続プールは、CPUのより有効に活用するために、CPUのアイドル時間が長く、待ち時間長く、スレッドの大きい数が、設定する必要があり、結果を返します。
注意:スレッドプールのスレッドがスレッドプール内のタスクのスクイズの作業をブロックされている場合は、最終的にシステム全体が使用不能に原因となりますので、有界キューを使用することをお勧めします
モニター・エレメント
- taskCount:あなたがスレッドプールを実行する必要があるタスクの数
- completedTaskCount:動作中のスレッドプール内のタスクの数が完了した、以下taskCount
- targetPoolSize:スレッドプール内のスレッドの最大数が作成されています。あなたは今までに、このデータによって、スレッド・プールまで速い1を引くことができます。
- getPoolSize:スレッドプール内のスレッド数。スレッドプールが破壊されていない場合は、スレッドプールのスレッドが自動的に破棄しないので、値は上昇しています
- getActiveCount:スレッドアクセス活動の数
スレッドプールを拡張することによって監視しました。あなたがスレッドプールを書き換え、継承によってスレッドプールのスレッドプールをカスタマイズすることができbeforeExecute()
、afterExecute()
、terminated()
この方法はまた、いくつかのコードの実行を監視するために、タスクの前に実行することができます。
概要
この記事では、スレッドプール、および監視の様々な要素を使用しているときに最適化された意味を理解することが主な理由です。