まず、スレッドプールは何ですか?
仕事をするために、スレッドプールは、実行中のスレッドの数を制御するために主にあるスレッドの数が最大数、ラインで待機しているスレッドの過剰数、および他のスレッドを超えた場合、タスクは、処理キューに追加して、スレッドの作成後にこれらのタスクを開始します完成し、その後、タスクを実行するためにキューから削除。
スレッドプールの主な機能は次のとおりです。スレッドの多重化、同時、スレッド管理の最大数を制御します。
第二に、スレッドプールの利点
- リソース消費を削減します。あなたが作成するスレッドを再利用することにより、消費によって引き起こされるスレッドの作成と破壊を減らします。
- 応答速度を向上させます。ミッションが到着すると、タスクは、スレッドの作成を直ちに実施することが可能になるまで待つ必要がないかもしれません。
- 管理性を向上させるスレッド。スレッドは希少資源である、無限の創造場合は、リソースを消費するだけでなく、スレッドプールを使用して、システムの安定性が低いが、配布を統一することができ、チューニングおよび監視だけではなく。
第三に、アーキテクチャを達成するために
プール内のJavaスレッドがキュータフレームワークによって実現され、我々は枠組みの中で執行、エグゼキュータ、ExecutorServiceの、ThreadPoolExecutorこれらのクラスを使用していました。
第四に、スレッドプールを作成するには、いくつかの方法が
4.0 ThreadPoolExecutor()
作成されたほとんどの元のスレッド・プール、以下はThreadPoolExecutorのためのパッケージを作成するには、トップ3の方法があります。
4.1 Executors.newFixedThreadPool(int型)
主な特徴は次の通りである:
1.は、スレッドプールされた固定長を作成し、キュー内のスレッドが待機を超えて同時スレッドの最大数を制御することができる。
、それはLinkedBlockingQueueを等しく使用される作成したプールとMaxmumPoolSize 2 newFixedThreadPool corePoolSizeスレッド。
4.2 Executors.newSingleThreadExecutor()
:主な機能は次の通りです
。1.すべてのタスクが指定された順序で実行されることを保証するために、タスクのみワーカースレッドを実行するためにのみ使用し、シングルスレッドのスレッドプールを作成します。
2. newSingleThreadExecutor corePoolSizeとMaxmumPoolSizeが1に設定されている、それはLinkedBlockingQueueを使用しています。
4.3 Executors.newCachedThreadPool()
主な機能は次のようにしている:
1.スレッドプールが処理するニーズよりも長い場合、キャッシュされるスレッドプールを作成し、柔軟性がアイドル状態のスレッドを回復し、リサイクルしていない場合は、新しいスレッドが作成されます。
スレッドはより60秒以上アイドル状態の場合に実行するスレッドを作成するタスクである2 newCachedThreadPool 0にcorePoolSizeセットは、MaxmumPoolSizeにInteger.MAX_VALUEを設定し、それがSynchronousQueueを使用しますが、それはスレッドを破壊します。
4.4 Executors.newWorkStealingPool()
ジャワ8を作成する方法はワークスチールアルゴリズム、並列処理タスクを使用して、内部にForkJoinPoolを構築し、添加し、処理の順序は保証されません。
4.5プロダクション使用
執行は、作成したカスタムThreadPoolExecutorを使用する必要性、実際の生産を使用せずに、スレッドプールを作成します。
並行処理に部分的にAlibabaの開発マニュアル:
カスタム・スレッド・プールを作成します:
1 public static void main(String[] args) { 2 ExecutorService threadPool = new ThreadPoolExecutor( 3 2, 4 5, 5 1L, 6 TimeUnit.SECONDS, 7 new LinkedBlockingQueue<>(3), 8 Executors.defaultThreadFactory(), 9 new ThreadPoolExecutor.AbortPolicy()); 10 11 try { 12 for (int i = 1; i <= 10; i++) { 13 threadPool.execute(() -> { 14 System.out.println(Thread.currentThread().getName() + "\t 办理业务"); 15 }); 16 } 17 } finally { 18 threadPool.shutdown(); 19 } 20 }
五、线程池中的几个重要参数
- corePoolSize:线程池中的常驻核心线程数。
- maximumPoolSize:线程池能够容纳的同时执行的最大线程数,此值大于等于 1。
- keepAliveTime:多余的空闲线程存活时间,当空闲时间达到 keepAliveTime 值时,多余的线程会被销毁,直到只剩下 corePoolSize 个线程为止。
- unit:keepAliveTime 的单位。
- workQueue:任务队列,被提交但尚未被执行的任务。
- threadFactory:表示生成线程池中工作线程的线程工厂,用户创建新线程,一般用默认即可。
- handler:拒绝策略,表示当线程队列满了并且工作线程大于等于线程池的最大线程数(maxnumPoolSize)时如何来拒绝。
六、线程池的底层工作原理
1. 在创建了线程池后,等待提交过来的任务请求。
2. 当调用 execute() 方法添加一个请求任务时,线程池会做如下判断:
2.1 如果正在运行的线程数量小于 corePoolSize,那么马上创建线程运行这个任务;
2.2 如果正在运行的线程数量大于或等于 corePoolSize,那么将这个任务放入队列;
2.3 如果这时候队列满了且正在运行的线程数量还小于 maximumPoolSize,那么还是要创建非核心线程立刻运行这个任务;
2.4 如果队列满了且正在运行的线程数量大于或等于 maximumPoolSize,那么线程池会启动饱和拒绝策略来执行。
3. 当一个线程完成任务时,它会从队列中取下一个任务来执行。
4. 当一个线程无事可做,超过一定的时间(keepAliveTime) 时,线程池会判断:
如果当前运行的线程数大于 corePoolSize,那么这个线程就被停掉。
所以线程池的所有任务完成后,它最终会收缩到 corePoolSize 的大小。
七、线程池的拒绝策略
当线程池中工作线程数达到 maximumPoolSize,且工作队列已满,那么就会执行拒绝策略处理任务,jdk 内置有四种拒绝策略。
拒绝策略 | 拒绝行为 |
AbortPolicy |
直接抛出 RejectedException 异常阻止系统正常运行 |
CallerRunsPolicy |
"调用者运行"一种调节机制,该策略既不会抛弃任务,也不会抛出异常,而是由提交任务者执行这个任务 |
DiscardOldestPolicy |
抛弃队列中等待最久的任务,然后把当前任务加入队列中尝试再次提交 |
DiscardPolicy |
タスクを破棄し、何の治療は、例外をスローしません。タスクが欠落している許可した場合、これが最善の戦略拒否です |
八、スレッドプールのパラメータの合理的な配分
まず、のSystem.out.println(Runtime.getRuntime()availableProcessors())、CPUは、現在の監査コンピュータを取得します。
8.1 CPU集約型
タスクが障害なく、多くの計算を必要とするCPUを集中的手段、フルスピードでCPUが実行されます。
CPU集約的なタスクのみおそらく真のマルチコアCPU上で(複数のスレッドにより)促進すること、およびシングルコアのCPUは、オープンいくつかのシミュレーションをするかどうかをマルチスレッド、タスクは、加速することができない合計CPUパワーためそれらの上。
:できるだけ少ないようなスレッドの数を設定するCPU集約型のタスク
の一般式:スレッドプール内のスレッドのCPUコア数を+1
8.2 IO集約型
- IO集約型のタスクのスレッドは、常にミッションにされていないので、あなたは* 2 CPUコアの数など、多くのスレッドとして設定する必要があります。
- IO集約型であり、タスクは混雑がたくさんあること、IOの多くを必要とします。IO集約型のタスクが待ちにCPUパワーの多くを無駄につながることができ、単一のスレッド上で動作します。そうであってもシングルコアCPUで、大幅に実行するプログラムを加速することができ、複数のスレッドでIO集約型のタスクを使用して、この加速度は主に、ブロッキング時間の使用が無駄になっています。
IO集中、最もスレッドがブロックされる場合、必要に複数のスレッドを設定する:
リファレンス式:CPUコア/(L閉塞因子)の数0.8と0.9との間の遮断因子
、例えば8コアCPUとして:8 /(1から0.9 )= 80件のスレッド