スレッドプールの種類とパラメータ設定の問題

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アルゴリズムを利用してタスクを並列に処理し、処理順序を保証しない.

  • ブロックキュー(runnableTaskQueue)

  • ArrayBlockingQueue:配列構造に基づく境界ブロックキューであり、このキューは先進的な先出し原則に従って要素をソートする.
  • LinkedBlockingQueue:チェーンテーブル構造に基づくブロックキューで、要素を先頭に並べ替えます.スループットは通常ArrayBlockingQueueより高い.スタティックファクトリメソッドExcutors.新FixedThreadPool()はこのキューを使用しています.
  • SynchronousQueue:要素を格納しないブロックキュー.各挿入操作は、別のスレッドが削除操作を呼び出すまで待たなければなりません.そうしないと、挿入操作は常にブロックされます.スループットはLinkedBlockingQueueより高いです.スタティックファクトリメソッドExcutors.新CachedThreadPool()はこのキューを使用しています.
  • PriorityBlockingQueue:優先度のある無境界ブロックキュー.

  • システム負荷


    パラメータの設定はシステムの負荷と直接関係があり、システム負荷関連パラメータ:
  • tasks、1秒あたり処理する最大タスク数
  • tasktime、各タスクの処理に要する時間
  • responsetime、システムはタスクの最大の応答時間を許可し、例えば各タスクの応答時間は2秒
  • を超えてはならない.

    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つの戦略を提供しています.
  • AbortPolicy:直接放出異常
  • CallerRunsPolicy:呼び出し先のスレッドのみでタスクを実行する
  • DiscardOledestPolicy:キュー内の最近のタスクを破棄し、現在のタスク
  • を実行します.
  • DiscardPolicy:処理せず、
  • を廃棄
    以上,スレッド数の計算についてCPUの場合は考慮していない.CPUの場合、例えば、スレッド数が50に達した場合、CPUが100%に達した場合、maxPoolSizeを60に設定しても適切ではない.この場合、システム負荷が毎秒1000個のタスクに長時間維持されると、オフラインプールの処理能力を超え、各タスクの処理時間を低減することができる.
    参照先:https://blog.csdn.net/zhouhl_cn/article/details/7392607