スレッドプールの種類とパラメータ設定の問題
4165 ワード
JDK1.5には強力なconcurrentパッケージ、スレッドプールの実装ThreadPoolExcutorが導入されています.
通常、開発者はExecutorsが提供する汎用スレッドプールの作成方法を利用して、異なる構成のスレッドプールを作成します.主な違いは、ExecutorServiceタイプまたは異なる初期パラメータです.
Executorsは現在、5つの異なるスレッドプール作成構成を提供しています. newCachedThreadPool()は、短時間の作業タスクを大量に処理するためのスレッドプールであり、スレッドをキャッシュして再利用しようとし、キャッシュされていないスレッドが使用可能になると、新しい作業スレッドが作成されます.スレッドのアイドル時間が60秒を超えると、キャッシュは終了し、削除されます.長い間アイドル状態になっている場合、このスレッドプールはリソースを消費することはなく、内部ではSynchronousQueueをワークキューとして使用します. newFixedThreadPool()は、固定サイズのスレッドプールを作成し、背後には無境界のワークキューが使用され、いつでもnThreads個のワークスレッドがアクティブです.これは、タスクの数がアクティブなキューの数を超えると、ワークキューでアイドルスレッドの出現を待つことを意味します.作業スレッドが終了すると、指定された数nThreadsを満たすために新しい作業スレッドが作成されます. newSingleThreadExcuteor()は、ワークスレッドの数が1に制限され、無境界のワークキューを操作することを特徴としているため、すべてのタスクが順次実行されることを保証し、最大1つのタスクがアクティブであり、使用者がスレッドプールインスタンスを変更することを許さないため、スレッドの数を変更することを回避することができる. newSingleThreadScheduledExcutor()とnewScheduleThreadPool(int corePoolSize)は、単一のワークスレッドか複数のワークスレッドかを区別するタイミングまたは周期的なワークスケジュールを作成します. newWorkStealingPool(int parallelism)は、よく無視されるスレッドプールであり、Java 8はこの作成方法に参加し、その内部にはForkJoinPoolが構築され、Work-stealingアルゴリズムを利用してタスクを並列に処理し、処理順序を保証しない.
ArrayBlockingQueue:配列構造に基づく境界ブロックキューであり、このキューは先進的な先出し原則に従って要素をソートする. LinkedBlockingQueue:チェーンテーブル構造に基づくブロックキューで、要素を先頭に並べ替えます.スループットは通常ArrayBlockingQueueより高い.スタティックファクトリメソッドExcutors.新FixedThreadPool()はこのキューを使用しています. SynchronousQueue:要素を格納しないブロックキュー.各挿入操作は、別のスレッドが削除操作を呼び出すまで待たなければなりません.そうしないと、挿入操作は常にブロックされます.スループットはLinkedBlockingQueueより高いです.スタティックファクトリメソッドExcutors.新CachedThreadPool()はこのキューを使用しています. PriorityBlockingQueue:優先度のある無境界ブロックキュー.
パラメータの設定はシステムの負荷と直接関係があり、システム負荷関連パラメータ: tasks、1秒あたり処理する最大タスク数 tasktime、各タスクの処理に要する時間 responsetime、システムはタスクの最大の応答時間を許可し、例えば各タスクの応答時間は2秒 を超えてはならない.
1.corePoolSize:
コアスレッドの数は、タスクが処理されなくても、コアスレッドが常に生存します.スレッド数がコアスレッド数より小さい場合、既存のスレッドが空いていても、スレッドプールは、既存のスレッド処理に直接渡すのではなく、新しいスレッドを作成してタスクを処理します.
コアスレッドはallowCoreThreadTimeoutがtrueに設定されている間にタイムアウトして終了し、デフォルトでは終了しません.
各タスクにはtasktime秒処理が必要であり、各スレッドは毎秒1/tasktime個のタスクを処理することができる.システムには1秒あたりtasks個のタスクがあるため、必要なスレッド数はtasks/(1/tasktime)、すなわちtasks*tasktime個のスレッド数である.
システムの1秒あたりのタスク数が100-1000で、タスクごとに0.1秒かかると仮定すると、10-100個のスレッドが必要で、コアスレッド数は10より大きいように設定しなければならない.具体的な数字は8020の原則、すなわち80%の場合、システムの1秒あたりのタスク数は、システムの80%の場合、1秒あたりのタスク数が200より小さく、最大1000の場合、20に設定することができる.
2.maxPoolSize:
スレッド数がコアスレッド以上で、タスクキューがいっぱいになると、スレッドプールはmaxPoolSizeに達するまで新しいスレッドを作成します.スレッド数が最大スレッド数に等しい場合、スレッドプールの処理能力を超えており、スレッドプールはタスクの処理を拒否して例外を放出します.
システム負荷が最大値に達すると、コアスレッド数はすべてのタスクを時間通りに処理できなくなり、スレッドを増やす必要があります.毎秒200個のタスクには20個のスレッドが必要で、毎秒1000個のタスクに達した場合、(1000-queueCapacity)*(20/200)=60個のスレッドが必要で、最大スレッド数を60に設定できます.
3.keepAliveTime:
スレッドの空き時間がkeepAliveTimeに達すると、スレッド数がcorePoolSizeに達するまでスレッドは終了します.allowCoreThreadTimeoutがtrueに設定場合、スレッド数が0になるまですべてのスレッドが終了します.
4.allowCoreThreadTimeout:
コアスレッドのアイドル終了を許可するかどうか.
5.queueCapacity:
タスクキュー容量.maxPoolSizeの説明から、タスクキューの容量はスレッドの変化に影響するため、タスクキューの長さも適切に設定する必要があることがわかります.
タスクキューの長さは、コアスレッドの数と、タスクに対するシステムの応答時間の要件に基づいています.キューの長さは次のように設定できます.
(corePoolSize/tasktime)*responsetime:20/0.1*2=400、つまりキュー長を400に設定できます.
キューの長さを設定しすぎると、タスクの応答時間が長くなります.以下の書き方は避けてください.
これは実際にはキュー長をIntegerに設定.MAX_VALUEは、スレッド数が常にcorePoolSizeになり、二度と増加しません.タスク数が急増すると、タスク応答時間も急増します.
6.RejectedExcutionHandler:飽和ポリシー
キューとスレッドプールがいっぱいになった場合、スレッドプールが飽和状態にあることを示す場合は、新しくコミットされたタスクに対して特別なポリシーを使用して処理する必要があります.このポリシーのデフォルト設定はAbortPolicyで、新しいタスクを処理できずに例外を投げ出すことを示します.JAVAは4つの戦略を提供しています. AbortPolicy:直接放出異常 CallerRunsPolicy:呼び出し先のスレッドのみでタスクを実行する DiscardOledestPolicy:キュー内の最近のタスクを破棄し、現在のタスク を実行します. DiscardPolicy:処理せず、 を廃棄
以上,スレッド数の計算についてCPUの場合は考慮していない.CPUの場合、例えば、スレッド数が50に達した場合、CPUが100%に達した場合、maxPoolSizeを60に設定しても適切ではない.この場合、システム負荷が毎秒1000個のタスクに長時間維持されると、オフラインプールの処理能力を超え、各タスクの処理時間を低減することができる.
参照先:https://blog.csdn.net/zhouhl_cn/article/details/7392607
スレッドプールの種類
通常、開発者はExecutorsが提供する汎用スレッドプールの作成方法を利用して、異なる構成のスレッドプールを作成します.主な違いは、ExecutorServiceタイプまたは異なる初期パラメータです.
Executorsは現在、5つの異なるスレッドプール作成構成を提供しています.
ブロックキュー(runnableTaskQueue)
システム負荷
パラメータの設定はシステムの負荷と直接関係があり、システム負荷関連パラメータ:
ThreadPoolExcutorクラスで設定できるパラメータは次のとおりです。
1.corePoolSize:
コアスレッドの数は、タスクが処理されなくても、コアスレッドが常に生存します.スレッド数がコアスレッド数より小さい場合、既存のスレッドが空いていても、スレッドプールは、既存のスレッド処理に直接渡すのではなく、新しいスレッドを作成してタスクを処理します.
コアスレッドはallowCoreThreadTimeoutがtrueに設定されている間にタイムアウトして終了し、デフォルトでは終了しません.
各タスクにはtasktime秒処理が必要であり、各スレッドは毎秒1/tasktime個のタスクを処理することができる.システムには1秒あたりtasks個のタスクがあるため、必要なスレッド数はtasks/(1/tasktime)、すなわちtasks*tasktime個のスレッド数である.
システムの1秒あたりのタスク数が100-1000で、タスクごとに0.1秒かかると仮定すると、10-100個のスレッドが必要で、コアスレッド数は10より大きいように設定しなければならない.具体的な数字は8020の原則、すなわち80%の場合、システムの1秒あたりのタスク数は、システムの80%の場合、1秒あたりのタスク数が200より小さく、最大1000の場合、20に設定することができる.
2.maxPoolSize:
スレッド数がコアスレッド以上で、タスクキューがいっぱいになると、スレッドプールはmaxPoolSizeに達するまで新しいスレッドを作成します.スレッド数が最大スレッド数に等しい場合、スレッドプールの処理能力を超えており、スレッドプールはタスクの処理を拒否して例外を放出します.
システム負荷が最大値に達すると、コアスレッド数はすべてのタスクを時間通りに処理できなくなり、スレッドを増やす必要があります.毎秒200個のタスクには20個のスレッドが必要で、毎秒1000個のタスクに達した場合、(1000-queueCapacity)*(20/200)=60個のスレッドが必要で、最大スレッド数を60に設定できます.
3.keepAliveTime:
スレッドの空き時間がkeepAliveTimeに達すると、スレッド数がcorePoolSizeに達するまでスレッドは終了します.allowCoreThreadTimeoutがtrueに設定場合、スレッド数が0になるまですべてのスレッドが終了します.
4.allowCoreThreadTimeout:
コアスレッドのアイドル終了を許可するかどうか.
5.queueCapacity:
タスクキュー容量.maxPoolSizeの説明から、タスクキューの容量はスレッドの変化に影響するため、タスクキューの長さも適切に設定する必要があることがわかります.
タスクキューの長さは、コアスレッドの数と、タスクに対するシステムの応答時間の要件に基づいています.キューの長さは次のように設定できます.
(corePoolSize/tasktime)*responsetime:20/0.1*2=400、つまりキュー長を400に設定できます.
キューの長さを設定しすぎると、タスクの応答時間が長くなります.以下の書き方は避けてください.
LinkedBlockingQueue queue=new LinkedBlockingQueue();
これは実際にはキュー長をIntegerに設定.MAX_VALUEは、スレッド数が常にcorePoolSizeになり、二度と増加しません.タスク数が急増すると、タスク応答時間も急増します.
6.RejectedExcutionHandler:飽和ポリシー
キューとスレッドプールがいっぱいになった場合、スレッドプールが飽和状態にあることを示す場合は、新しくコミットされたタスクに対して特別なポリシーを使用して処理する必要があります.このポリシーのデフォルト設定はAbortPolicyで、新しいタスクを処理できずに例外を投げ出すことを示します.JAVAは4つの戦略を提供しています.
以上,スレッド数の計算についてCPUの場合は考慮していない.CPUの場合、例えば、スレッド数が50に達した場合、CPUが100%に達した場合、maxPoolSizeを60に設定しても適切ではない.この場合、システム負荷が毎秒1000個のタスクに長時間維持されると、オフラインプールの処理能力を超え、各タスクの処理時間を低減することができる.
参照先:https://blog.csdn.net/zhouhl_cn/article/details/7392607