JAVAスレッドプールExecutorService学習

4127 ワード

ExecutorServiceスレッドプールの総インタフェース.
ThreadPoolExecutor
はい
Executors
クラスの最下位実装.
ThreadPoolExecutorの完全な構造方法の署名は、ThreadPoolExecutor (int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)である.
CorePoolSize-空きスレッドを含むプールに保存されているスレッドの数.
maximumPoolSize-プールで許容される最大スレッド数.
keepAliveTime-スレッド数がコアより大きい場合、終了前に余分な空きスレッドが新しいタスクを待機する最長時間です.
unit-keepAliveTimeパラメータの時間単位.
WorkQueue-実行前にタスクを保持するキュー.このキューは、executeメソッドによってコミットされたRunnableタスクのみを保持します.
threadFactory-プログラムを実行して新しいスレッドを作成するときに使用するファクトリ.
handler-スレッド範囲とキュー容量を超えたため、ブロックされたときに使用されるプロセッサを実行します.
スレッドプールの動作原理は、corePoolSizeコアスレッド数を初期に作成するスレッドプールです.タスクキューがタスクを追加するときに、コアスレッドが空いている場合は、コアスレッドが直接実行されます.タスク数がコアスレッド数より大きい場合は、キューに入れて実行を待機します.タスクキューがいっぱいになると、現在のスレッド数が最大作成可能なスレッド数より小さいかどうかを判断します.より小さい場合は、スレッド実行を作成します.作成したスレッドの数が最大スレッド数に達し、タスクキューがいっぱいになった場合、破棄ポリシーが実行されます.
タスクキューの3つの実装方法:
SynchronousQueue:スレッドプール行にタスクを直接コミットし、自分で1つのタスクしか保存しません.タスクを1つ置いた後、タスクを置くと、キューにスレッドが取り外されていない場合は、スレッドを作成できるかどうかを判断します.作成できない場合は、破棄ポリシーを実行します.通常、無限スレッドプールと組み合わせて使用されます.
LinkedBlockingQueue:境界のないタスクキューで、使用時のスレッドプールの最大制限は無効です.コアスレッド数のスレッドのみが動作します.大量のタスクが瞬時に発生する可能性のあるシーンに適用します.
ArrayBlockingQueue:限られたスレッド数に合わせて境界のあるキュー.資源の枯渇による崩壊を防ぐ.
破棄ポリシーのデフォルト実装には4つの実装があります.
DiscardPolicy:何もしないで、直接捨てます.
DiscardOldestPolicy:最も古いタスクを破棄します.
AbortPolicy:タスクを捨てて異常を投げ出す.
CallerRunsPolicy:タスクスレッドに自分でタスクを処理させます.
4つのスレッドプールの実装を提供します.この4つのスレッドプールの最下位は
ThreadPoolExecutorは異なる構造パラメータに基づいて実現される.
1、SingleThreadExecutor:単一スレッドプールで、事のシリアルを保証できる.スレッドが切れた場合、スレッドが再作成され、作業が続行されます.corePoolSizeとmaxnumはいずれも1であり,生存時間は0であった.タスクキューは無限キューです.
2、FixedThreadExecutor:スレッド数の固定サイズのスレッドプールを作成する.作成時、corePoolSizeはmaxnumPoolSizeと同様に、スレッドプールのサイズを入力します.生存時間は0秒で、ずっと生存することを意味します.workQueueはLinkedBlockingQueueを採用し、無限タスクキューである.
3、CacheThreadExecutor:タスク数に応じてスレッド数を動的に維持する.タスク数がコア実行スレッド数を超え、最大スレッド数未満の場合、最大スレッド数まで新しいスレッドが作成されます.これは無限サイズのスレッドプールです.coreは0,maxはint最大値,生存時間は60秒であった.キューはSynchronousQueueを使用します.
4、ScheduledThreadExecutor:定期的なタスクを実行するための無限サイズのスレッドプールを作成します.
スレッドプールを合理的に構成するには、まずタスクの特性を分析する必要があります.以下のいくつかの角度から分析できます.
  • タスクの性質:CPU密集型タスク、IO密集型タスク、混合型タスク.
  • タスクの優先度:高、中和低.
  • タスクの実行時間:長、中和短.
  • タスクの依存性:データベース接続などの他のシステムリソースに依存するかどうか.

  • タスクの性質の異なるタスクは、異なる規模のスレッドプールで別々に処理できます.CPU密集型タスクは、Ncpu+1スレッドのスレッドプールを構成するなど、できるだけ少ないスレッド数を構成します.IO密集型タスクは、IO操作を待つ必要があるため、スレッドが常にタスクを実行しているわけではないので、2*Ncpuのようなできるだけ多くのスレッドを構成します.ハイブリッド型のタスクは、分割可能であれば、CPU密集型タスクとIO密集型タスクに分割されます.この2つのタスクの実行時間の差があまり大きくない限り、分解後のスループットはシリアル実行のスループットよりも高く、この2つのタスクの実行時間の差が大きすぎる場合は、分解する必要はありません.私たちはRuntimeを通じてgetRuntime().AVailableProcessors()メソッドは、現在のデバイスのCPU個数を取得する.
    優先度の異なるタスクは、優先度キューPriorityBlockingQueueを使用して処理できます.優先度の高いタスクを先に実行することができます.優先度の高いタスクがキューにコミットされている場合、優先度の低いタスクは永遠に実行できない可能性があります.
    実行時間の異なるタスクは、異なる規模のスレッドプールに渡して処理するか、優先度キューを使用して、実行時間の短いタスクを先に実行することもできます.
    データベース接続プールのタスクに依存します.スレッドがSQLをコミットした後、データベースの戻り結果を待つ必要があるため、待機時間が長ければ長いほどCPUの空き時間が長くなる場合は、スレッド数を大きく設定してこそ、CPUをよりよく利用することができます.
    有界キューを使用することをお勧めします.有界キューはシステムの安定性とアラート能力を増加させ、必要に応じて数千などの大きな設定ができます.ある時、私たちのグループが使用したバックグラウンドタスクスレッドプールのキューとスレッドプールがいっぱいになって、絶えずタスクを捨てる異常を投げ出して、調査を通じてデータベースに問題が発生したことを発見して、SQLの実行が非常に遅くなって、バックグラウンドタスクスレッドプールのタスクはすべてデータベースにデータを照会して挿入する必要があるため、スレッドプールの中の作業スレッドはすべてブロックされて、タスクがラインプールに蓄積されます.無境界キューに設定すると、スレッドプールのキューがますます多くなり、バックグラウンドタスクだけでなくシステム全体が使用できなくなる可能性があります.もちろん、システムのすべてのタスクは個別のサーバで導入されていますが、異なる規模のスレッドプールを使用して異なるタイプのタスクを実行していますが、このような問題が発生した場合、他のタスクにも影響します.
    スレッドプールから提供されるパラメータで監視します.スレッドプールには、スレッドプールを監視するときに使用できるプロパティがあります.
  • taskCount:スレッドプールで実行するタスクの数.
  • completedTaskCount:スレッドプールが実行中に完了したタスクの数.taskCount以下.
  • largestPoolSize:スレッドプールが作成した最大スレッド数.このデータにより、スレッドプールが満たされているかどうかを知ることができます.スレッドプールの最大サイズに等しい場合は、スレッドプールがいっぱいになったことを示します.
  • getPoolSize:スレッドプールのスレッド数.スレッドプールが破棄されなければ、プール内のスレッドは自動的に破棄されないので、このサイズは増減しません.
  • getActiveCount:アクティブなスレッド数を取得します.