Javaスレッドプールの分析

著作権:コードワードは容易ではない、ソースを明記してください~~ https://blog.csdn.net/m0_37190495/article/details/84849334
再現、ソースを明記してください:
:オリジナルはで始まる http://www.zhangruibin.com
から記事 RebornChangさんのブログ

臆面もなく広告、ブロガー個人のブログでは対処ポータル、ようこそ

あまりにも長い間に書かれたコード、次は、自分のスキルツリーを作成し、何かが欠けている、だから、今開いて、彼らの旅を記念ちょうど助けるためにジュニアパートナーを入力し、希望するだけでなく、ブロガーを共有するために書き留め見ますコード。

何がスレッドプールの下にあることを、まず、

データベース接続プールに似たスレッド・プール、ThreadPoolの、。データベース接続プールは、スレッドプールは、スレッド管理によって開催される、データベース接続の管理を保持されています。
一部の人々が求めることができる、スレッドは何ですか?何のライフサイクルを通し?スレッドを作成する方法はいくつかありますか?意味の優先度のスレッド?
ここでは前の文、上記スレッドに関するこれらの質問は、必要が説明して開かれます場合は、この章で説明していません。

クラスの基本的な関係を実行するスレッドプールの実装を継承ThreadPoolExecutor

エグゼキュータ

エグゼキュータが実行可能タイプ、文字通りの意味で理解されるパラメータが単一のメソッドは、(Runnableを)実行されるトップレベルインターフェース、ボイド戻り値であり、タスクを実行する際に渡すために使用されます。

ExecutorServiceの

ExecutorServiceのインターフェイスは、エグゼキュータ・インターフェースを拡張し、いくつかの方法を宣言していますように、invokeAllを提出invokeAnyシャットダウンと;

AbstractExecutorService

AbstractExecutorService ExecutorServiceの抽象クラスは、インタフェース、ExecutorServiceの中で宣言基本的にすべてのメソッドを実装します。

ThreadPoolExecutor

いくつかの重要な実装方法がありThreadPoolExecutor継承したクラスAbstractExecutorService、:

()を実行します。

execute()メソッドは、実際に具体的ThreadPoolExecutorで実装エグゼキュータが宣言方法、である、この方法は、ThreadPoolExecutorコア法である、あなたが実行するスレッドプールに引き渡さ、この方法により、スレッド・プールにジョブを送信することができます。

提出():

(()メソッドは、ExecutorServiceの中で宣言されたメソッドで、すでにそれはAbstractExecutorServiceで特定の実装を持っている、とThreadPoolExecutorに書き換えることがない、このメソッドは、スレッド・プールにジョブを送信するために使用されますが、提出して実行します)別の方法を、それを達成するために提出する()メソッドを参照してください、タスクの実行結果を返すことが可能である、あなたは実行ができます()メソッドは、実際に呼び出されるが、それは(今後のコンテンツの意志タスクの実行結果を得るために、将来を利用しています)次の話で。

シャットダウン():

タスクスレッドを実行した後、スレッドプールが閉じられます。

shutdownNowの():

現在のスレッドが完了していない場合は、現在のスレッドに実行タスクを打破しようとすると、スレッドプールを閉じます。

解釈ThreadPoolExecutorのいくつかの重要なパラメータ

corePoolSize

このパラメータの原理の実現とプールのコアサイズは、スレッドプールは素晴らしい関係を持って伝えます。あなたは、デフォルトでは、スレッドプール、スレッドプールなしのスレッドを作成しますが、タスクの到着を待った後、あなたはprestartAllCoreThreads(呼び出さない限り、タスクを実行するためのスレッドを作成することでした)またはprestartCoreThread()メソッド、2のこの方法名前は、タスクが来ていない前に、スレッドまたはスレッドcorePoolSizeを作成する意味の事前作成されたスレッドを、見ることができます。あなたは、スレッドプールを作成した後、デフォルトでは、スレッドプール内のスレッドの数は、スレッドプール内のスレッドの数がcorePoolSizeに達した場合、後で、それは、タスクを実行するスレッドを作成しますするタスクがある場合、0で到達しますタスクがキャッシュにそれらをキュー。

maximumPoolSize

スレッドプール内のスレッドの最大数は、このパラメータは、スレッドプール内のスレッドの最大数を表す非常に重要なパラメータは、作成することが可能です。

keepAliveTimeが

これは、タスクの実行が終了すると、スレッドは長い時間まで保持していないことを示しています。corePoolSizeよりも、スレッドプール内のスレッドの数が大きくなると、スレッドがアイドル状態の場合、デフォルトでは、スレッドプール内のスレッドの数がcorePoolSizeより大きくなくなるまで、スレッドプール内のスレッドの数がcorePoolSizeよりも大きい、keepAliveTimeがが動作するときにのみ、それは、ありますプール内のスレッドの数がcorePoolSizeを超えないまでkeepAliveTimeがに達するまでの時間は、終了します。あなたはallowCoreThreadTimeOut(boolean)メソッドを呼び出した場合、スレッドプール内のスレッド数が0になるまでしかし、スレッドプール内のスレッドの数がcorePoolSize以上でないとき、keepAliveTimeがパラメータが遊びに来ます。

単位

KeepAliveTimeの単位時間パラメータは、値の7種類があり、図7は、TimeUnitでクラスの静的プロパティです。

TimeUnit.DAYS;

TimeUnit.HOURS; H

TimeUnit.MINUTES;分

TimeUnit.SECONDS; sの

TimeUnit.MILLISECONDS; MS

TimeUnit.MICROSECONDS; 微妙

TimeUnit.NANOSECONDS; NS

ワークキュー

ブロッキングキューが実行を待っているタスクを格納するために使用され、このパラメータの選択は、スレッドプールの動作中に、また非常に重要である重要な影響を持つことになります、一般的には、ここでキューを遮断するには、3つのオプションがあります。

ArrayBlockingQueue

LinkedBlockingQueue

SynchronousQueue

注意:このパラメータは、キューキューjava.util.concurrentパッケージと、次のjava内の一部である、興味を持っている差の特性を理解するために、関連する情報は、各種のキューとの違いを見てアクセスするために行くことができますが、なぜ知っているのThreadPoolと組み合わされ3キューを選択します。

threadFactory

メインスレッドの作成に使用するスレッドファクトリ。

ハンドラ

彼は、処理タスク、以下の4つの値の時とき方針を示すことを拒否しました。

ThreadPoolExecutor.AbortPolicy

タスクを破棄し、例外をスローRejectedExecutionException。

ThreadPoolExecutor.DiscardPolicy

また、タスクを破棄しますが、例外をスローしません。

ThreadPoolExecutor.DiscardOldestPolicy

一番のタスクキューを破棄して、タスク(このプロセスを繰り返し)を再実行してみてください。

ThreadPoolExecutor.CallerRunsPolicy

呼び出し元のスレッドによってタスク処理。
PS:ここで彼はThreadPoolExecutorを宣言している場合、我々はまず、最大容量(maxmumPoolSize + QUEUESIZE)を越えた後、アボート戦略を使用して、スレッドの実行を疑いの種を植え、これはスレッドプールの正常な動作を保証することができますが、明らかではありません当社の生産に合わせてどのように行うには、中断した後、スレッドが実行されるため、生産タスクを論理的使用?だから、ここでのポイントを植えです:合理的なスレッドプールを作成する方法?

クラスのいくつかの重要なメンバ変数とThreadPoolExecutorを説明

民間最終BlockingQueueのワークキュー。

実行されるのを待っているタスクを格納するために使用されるタスクのバッファキュー;

新しい民間最終ReentrantLockのmainLock ReentrantLockの=();

ロックスレッドプールの主な条件は、スレッドプールは、ロックを使用しなければならない(等スレッドプールのサイズ、runState、など)のステータスを変更します。

民間最終HashSetの労働者=新しいHashSetの();

ワーキングセットを格納するために使用されます。

プライベート揮発長いkeepAliveTimeが。

スレッドの生存期間。

プライベート揮発ブールallowCoreThreadTimeOut。

コアスレッドとして設定されている生存時間を許可するかどうか。

プライベート揮発int型corePoolSize。

プールのコアサイズ(プール内のスレッドの数、すなわち、このパラメータよりも大きい場合、タスクがタスクキューバッファに送信されます)。

プライベート揮発int型maximumPoolSize。

スレッドプール内のスレッドの最大数が許容することができます。

プライベート揮発int型プールサイズ。

スレッドプール内のスレッドの現在の数。

プライベート揮発性のRejectedExecutionHandlerハンドラ。

ミッションは、戦略を拒否しました。

プライベート揮発性ThreadFactory threadFactory。

スレッドの作成に使用するスレッドファクトリ。

プライベートint型largestPoolSize。

スレッドプールのスレッドの最大数は、一度これまでの記録登場しました。

プライベート長いcompletedTaskCount。

タスクの実行を完了した回数を記録します。

corePoolSizeとmaximumPoolSizeについて

説明するためにオンラインの例を借りて:
工場、10人の労働者を持っている工場がある場合は、各ワーカーは、同時に一つのタスクを行うことができます。
だから、限り10人の労働者として労働者は労働者が行うアイドルに割り当てられたタスクに自由であるとき、
それがタスクにある場合には10人の労働者は、実行するタスクを持っている場合、タスクの待ちを入れて、
もし新しい仕事の成長の数のタスクを行うには、労働者の速度よりもはるかに高速で、その後、時間の植物スーパーバイザがでてくるような再募集4人の派遣労働者として改善措置に必要がある場合があります。
その後、タスクが何をし4人の一時的な労働者に割り当てられます。
もし彼は、その後、プラントマネージャは、新しいタスクを取るか、前のタスクの一部を放棄しないよう考慮しなければならない場合があり、タスクの速度を行うための14人の労働者が十分ではないと述べました。
アイドルだったこれらの14人の労働者と、新しいタスクと比較的遅い成長率は、工場長は、4人の一時的な労働者を辞め検討するかもしれないときは、ちょうどすべての後に、余分なお金の労働者を作ることです、オリジナルの10人の労働者を保つためにA。
この例ではCorePoolSizeは10であり、maximumPoolSize 14(10 + 4)です。
それがcorePoolSizeスレッドプールサイズで、私の意見でmaximumPoolSizeが、救済のスレッドプールで救済そのときにタスクの突然の大量。
しかし、理解を容易にするため、以降この記事では、corePoolSizeコアプールサイズに変換されます。
いくつかの場所で、非常に良いで書かれていますが、JDK1.6のために解析されている記事は、このようなスレッドプールを作成する方法だけでなく、内部メソッドThreadPoolExecutor実装として、JDK1.8に変更されることがあります。

スレッドプールを使用します

ThreadPoolExecutorを作成した基盤を使用して、パラメータのサイズを指定

     package com.example.test.threadPool;

     import java.util.concurrent.*;

     /*
     * @ClassName TestThreadPool
     *@Description TODO  测试线程池的基本使用方法
     *@Author zhangrui
     *@Date 2018/12/5 9:48
     *@Version 
     */
     public class TestThreadPool {
         public static void main(String[] args) {
             //1.声明线程池执行器
             //参数,corePoolSize,maxmumPoolSize,keepAliveTime,TimeUnit,queue.
             //其中queue通常选择ArrayBlockingQueue,LinkedBlockingQueue,SynchronousQueue.
             //TimeUnit有七种取值,可以精确到NanoSeconds(纳秒级别)
             //根据日志的打印,就是先将线程加入到corePoolSize中,当corePoolSize满了之后加入到队列中,队列满了就向maxmumPoolSize-corePoolSize中加入。
             //当值达到maxmumPoolSize+queueSize之后,再有任务就会启用abort策略,abort策略有四种,可参考源码理解
             //FIXME 这种创建线程池的方法是不推荐使用的,因为当线程量超过最大存储容量的时候会抛出拒绝任务异常
             ThreadPoolExecutor executor = new ThreadPoolExecutor(5,10,200, TimeUnit.MILLISECONDS,new ArrayBlockingQueue<Runnable>(5));
             //i=maxmumPoolSize+queueSize
             for (int i = 0;i<15;i++){
                 //2.获取线程执行的任务
                 Mytask mytask = new Mytask(i);
                 //3.将线程放入执行器中执行,也可以使用submit方法,但是submit方法底层调用的也是execute方法,只是submit有参数返回值
                 executor.execute(mytask);
                 System.out.println("线程池中线程数目:"+executor.getPoolSize()+",队列中等待执行的任务数目:"+
                         executor.getQueue().size()+",已执行完别的任务数目:"+executor.getCompletedTaskCount()
                 +",线程池中存活线程数目:"+executor.getActiveCount());
             }
             //4.停止执行器,shutdown是在线程执行完任务后结束,shutdownNow会尝试中断线程中所执行的任务停止执行器
             executor.shutdown();
         }


         //声明一个内部类,实现Runnable,声明线程任务
         private static class Mytask implements Runnable{
             private int taskNum;
             public Mytask(int num){
                 this.taskNum = num;
             }
             @Override
             public void run() {
                 System.out.println("正在执行task "+taskNum);
                 try {
                     Thread.currentThread().sleep(3000);
                 } catch (InterruptedException e) {
                     e.printStackTrace();
                 }
                 System.out.println("task "+taskNum+"执行完毕");
             }
         }
     }

上記出力実行コードは以下の通りであります:

   正在执行task 0
   线程池中线程数目:1,队列中等待执行的任务数目:0,已执行完别的任务数目:0,线程池中存活线程数目:1
   线程池中线程数目:2,队列中等待执行的任务数目:0,已执行完别的任务数目:0,线程池中存活线程数目:2
   正在执行task 1
   线程池中线程数目:3,队列中等待执行的任务数目:0,已执行完别的任务数目:0,线程池中存活线程数目:3
   正在执行task 2
   线程池中线程数目:4,队列中等待执行的任务数目:0,已执行完别的任务数目:0,线程池中存活线程数目:4
   正在执行task 3
   线程池中线程数目:5,队列中等待执行的任务数目:0,已执行完别的任务数目:0,线程池中存活线程数目:5
   线程池中线程数目:5,队列中等待执行的任务数目:1,已执行完别的任务数目:0,线程池中存活线程数目:5
   正在执行task 4
   线程池中线程数目:5,队列中等待执行的任务数目:2,已执行完别的任务数目:0,线程池中存活线程数目:5
   线程池中线程数目:5,队列中等待执行的任务数目:3,已执行完别的任务数目:0,线程池中存活线程数目:5
   线程池中线程数目:5,队列中等待执行的任务数目:4,已执行完别的任务数目:0,线程池中存活线程数目:5
   线程池中线程数目:5,队列中等待执行的任务数目:5,已执行完别的任务数目:0,线程池中存活线程数目:5
   线程池中线程数目:6,队列中等待执行的任务数目:5,已执行完别的任务数目:0,线程池中存活线程数目:6
   正在执行task 10
   线程池中线程数目:7,队列中等待执行的任务数目:5,已执行完别的任务数目:0,线程池中存活线程数目:7
   线程池中线程数目:8,队列中等待执行的任务数目:5,已执行完别的任务数目:0,线程池中存活线程数目:8
   线程池中线程数目:9,队列中等待执行的任务数目:5,已执行完别的任务数目:0,线程池中存活线程数目:9
   线程池中线程数目:10,队列中等待执行的任务数目:5,已执行完别的任务数目:0,线程池中存活线程数目:10
   正在执行task 12
   正在执行task 13
   正在执行task 11
   正在执行task 14
   task 0执行完毕
   正在执行task 5
   task 1执行完毕
   正在执行task 6
   task 3执行完毕
   正在执行task 7
   task 2执行完毕
   task 4执行完毕
   正在执行task 9
   正在执行task 8
   task 12执行完毕
   task 13执行完毕
   task 11执行完毕
   task 10执行完毕
   task 14执行完毕
   task 6执行完毕
   task 9执行完毕
   task 5执行完毕
   task 8执行完毕
   task 7执行完毕

   Process finished with exit code 0

スレッドプールのパラメータは、手立て自動的に実行する必要がある場合、スレッドプールの最大容量内のスレッドの数よりも大きい、それはされますされ、現在の生産タスクに基づいて適応していない死者を書くことです:唯一の最も基本的な実装上のコードでは、大きな問題があります戦略の実行中止。したがって、これは、Javaドキュメントに、直接使用ThreadPoolExecutorを促進しないが、セクションに示すように実施例で提供されるいくつかの静的メソッドを使用して、スレッドプールクラスエグゼキュータを作成するために、スレッドプール剛性方法を作成します。

スレッドプールを作成するための一般的な方法

Executors.newCachedThreadPool();

バッファー・プールの作成、プールのサイズがInteger.MAX_VALUEのサイズです。

Executors.newSingleThreadExecutor();

容量のプールを作成します。

Executors.newFixedThreadPool(INT);

容量の大きさの固定されたプールを作成します。

ビューのその具体的な実現から、彼らは実際にThreadPoolExecutorを呼び出しますが、パラメータが設定されています。corePoolSize maximumPoolSizeスレッドプールおよび値等しいnewFixedThreadPoolが作成され、それはLinkedBlockingQueueを使用して、newSingleThreadExecutor maximumPoolSize corePoolSizeと1に設定され、LinkedBlockingQueueも使用; newCachedThreadPool corePoolSizeが0に設定、maximumPoolSize Integer.MAX_VALUEの設定、使用スレッドが60秒以上アイドル状態のときSynchronousQueueは、そのスレッドの実行を作成するタスクに言うことです、それはスレッドを破壊します。実際には、要件を満たすために設けられた3つの静的メソッドエグゼキュータ場合、我々は、彼らが手動で実際のタスクの種類と量に応じて設定されるパラメータThreadPoolExecutor少し問題を、設定するために行くので、それは、3つのメソッドを提供して使用するようにしてください。また、標準以下ThreadPoolExecutor場合、クラスには、彼のThreadPoolExecutorの書き換えが継承することができます。
注:Jdk1.8は別の方法で接合された後(INT並列)/ newWorkStealingPool()を作成newWorkStealingPool 、 注釈付きメソッドは、おそらく意味:
スレッドプールを作成するために、スレッドプールのスレッドが十分なサポートを与えられたレベルの並列性を維持しますそして複数のキューは、競合を減少させるために使用されてもよいです。積極的に参加又はタスク処理するために使用することができるスレッドの最大数に応じた並列処理レベル。スレッドの実際の数は動的に成長し、縮小することができます。プールを盗む作業が実行提出タスクの順序を保証することはできません。

追記:ここで説明します次のブログ記事では、いくつかの質問に滞在する:
1.公式のスレッドプールを作成する方法をお勧めします、私は十分にカスタマイズ確立アボートが自分の戦略を開発することができないと感じたら?
2.関係でどのようなスレッドプールとマルチスレッドは、どのように使用するには?
3. volatileキーワードの原則源は何ですか?
興味のパートナーは、スレッドプールに、マルチスレッドやその他のコンテンツを継続的に更新され、Uを参照してください、この小さなブログに焦点を当てることができます...

おすすめ

転載: blog.csdn.net/m0_37190495/article/details/84849334