I.はじめにスレッドプール
そして、①スレッドプールを使用すると、実行するために、新しいスレッドに直接非同期タスクを実行したいとき、スレッドプールの時間を使用せずに、非同期タスクを多数実行する際に、より良いパフォーマンスを提供するために:主に二つの問題を解決するためにされたスレッドプールを使用します、スレッドの作成と破壊がオーバーヘッドを必要としています。プール内のスレッド再使用可能であり、各時間が再作成および破棄するために、非同期タスクを実行する必要がないスレッド、②リソースの制限と管理ツールを提供するスレッドプールのようなスレッドの数を制限することができ、動的新しいスレッドのように。
二、ThreadPoolExecutorクラス
1、我々は簡単にメンバ変数とそれが表す意味でThreadPoolExecutorのいくつかを見て
タイプ整数CTL原子変数のメンバ変数である継承におけるThreadPoolExecutor AbstractExecutorServiceは、と同様スレッドプールとスレッドプールの状態を記録するために使用されるスレッドの数は、前述した読み取り書き込みロックを両者を保持するために変数を使用して情報の種類。ここで(整数32を見た)スレッドプール29内のスレッドの三CTL高い番号が後ろに、スレッドプールの状態を表します。ソースコード内のメンバー変数を以下のようにそれはThreadPoolExecutor
1 // (3ビット)は、スレッドプールの状態を示し、(下位29ビット)スレッドプール内のスレッドの数を示し、 2 // デフォルトはRUNNING状態で、スレッドプールの数は0である 。3 プライベート 最終のAtomicInteger CTLの= 新しい新 AtomicInteger(ctlOf(RUNNING、0 )); 4 。5 // スレッドの数は後-3以下の特定のプラットフォームで表されるビットの整数残りのビット数で表し、 6 // 請求Integer.SIZE = 32、スレッドの下位29ビット数は、以下-3で表される 。7 プライベート 静的 最終 INT COUNT_BITS Integer.SIZE = - 3。; 8。 9。 // スレッドの最大数(低い29)00011111111111111111111111111111(1 << 29-1) 10 プライベート 静的 最終 int型=容量(COUNT_BITS << 1。) - 1 ; 11 12である // スレッドプールの状態(ハイ状態3は、スレッドプールを示す) 13であり、 // 111 00000000000000000000000000000 14 プライベート 静的 最終 INT RUNNING = -1 << COUNT_BITS; 15 16 // 000 00000000000000000000000000000 。17 プライベート 静的 最終 INT SHUTDOWN = 0 << COUNT_BITS; 18である 。19 // 001 00000000000000000000000000000 20は、 プライベート 静的 最終 INT。STOP = << 1 COUNT_BITS; 21であります 22 // 010 00000000000000000000000000000 23 プライベート 静的 最終 int型の片付け= 2 << COUNT_BITS。 24 25 // 011 00000000000000000000000000000 26 プライベート 静的 最終 int型 TERMINATED = 3 << COUNT_BITS。 27 28 // 获取高3位(运行状态)==> C&11100000000000000000000000000000 29 プライベート 静的 int型 runStateOf(int型 C){ リターン C&〜CAPACITY。} 30 31 //下位29ビット(スレッド数)を取得する==> 00011111111111111111111111111111&C 32 プライベート 静的 INT workerCountOf(INT C){ 戻り C&容量;} 33は 34である 。// 新しい値原子が可変(動作状態とスレッドの数)をCTL計算 35 プライベート 静的な int型 ctlOf(int型 RS、int型 WC){ 戻り RS | WC;}
ここでは、上記で簡単にスレッド状態の意味を説明します。
①RUNNING:キューを遮断する新しいタスクおよび処理タスクを受け入れます
②SHUTDOWN:新しいタスクが、ブロッキングキューのタスクに対処することを拒否しました
③STOP:新しいタスクとは、ブロッキングキューのタスクを放棄することを拒否し、それが現在実行中のタスクを中断します
④TIDYING:スレッドプール内のアクティブなスレッドの現在の数のすべてのタスク(タスクがキューブロッキング含む)を行った後は、この方法が終了と呼ばれる、ゼロであります
⑥TERMINATED:終了ステータス。終了メソッドの呼び出し後の状態
パラメータについての予備的な理解とThreadPoolExecutorの原則の実現以下の2、
①corePoolSize:車の数は現在、スレッドプールの中核であります
②workQueue:(アレイベースはLinkedBlockingQueueなど無制限のブロッキングキューのリストに基づいて、キューArrayBlockingQueueを遮断囲まれたような)ブロッキングキューのタスクを実行するタスクを待ち保存
③maximumPoolSize:スレッドプール内のスレッドの最大数
④ThreadFactory:スレッドファクトリを作成します。
⑤RejectedExecutionHandler:ポリシーを拒否、キューがいっぱいのとき取ら提出戦略のための新しいタスクは、4つの主要な戦略がある場合、スレッドプール内のスレッドの数はスレッドの最大数に達したことを意味しますAbortPolicy(スロー)、CallerRunsPolicy(のみ発信者をスレッドは、タスクを実行する場合)、DiscardOldestPolicy()現在提出されたタスクを処理するためのブロッキングキューの最近の仕事を失う、処理せずにDiscardPolicy(直接は破棄)
⑥keepAliveTime:生存時間、プール内のスレッドの現在の数が、スレッドのコアの数、および現在のスレッドがアイドルよりもあれば、この変数は、これらのスレッドの最大生存時間であります
⑦TimeUnit:単位時間当たりの生存時間。
導入された上記のパラメータによると、出発点として、新しいタスクを送信するために実装原則スレッドプール、メインの処理フロー解析スレッドプールを簡単に見
3、スレッドプールのいくつかの種類の使用に
①newFixedThreadPool:スレッドのコア数とスレッドの最大数を作成しているnthreadsの値のスレッドプール、およびブロッキングInteger.MAX_VALUEでのキュー長、keepAliveTimeが= 0限り、芯糸よりもスレッドの数が現在アイドル状態である命令の数とそれが回収されます。
パブリック 静的 ExecutorServiceのnewFixedThreadPool(INT nthreadsの値){ 戻り 新しいThreadPoolExecutor(nthreadsの値、nthreadsの値、 0L 、TimeUnit.MILLISECONDS、 新しい LinkedBlockingQueue <Runnableを> ()); }
②newSingleThreadExecutor:keepAliveTimeが= 0であれば、スレッドの数などのコアスレッドの説明数よりスレッドプール1、キューおよびブロックInteger.MAX_VALUEの長さ、糸のコアの数とスレッドの最大数を作成し、現在のスレッドを回収すること、すなわちアイドル状態スレッド。
パブリック 静的ExecutorServiceのnewSingleThreadExecutorは(){ 戻り 新しいFinalizableDelegatedExecutorService (新しい ThreadPoolExecutor(1、1 、 0L 、TimeUnit.MILLISECONDS、 新しい LinkedBlockingQueue <Runnableを> ()))。 }
③newCachedThreadPoolExecutor:オンデマンドで作成されたスレッドプールのスレッドを作成し、番号0は、スレッドInteger.MAX_VALUEの数まで、最初のスレッドで同期キューおよびキューが(せいぜい1要素)ブロックされている、keepAliveTimeが= 60があれば、現在のスレッドの60年代ことを実証していますアイドルが回収されます。スレッドプールのこのタイプの特徴は次のとおりです。タスクの同期はキューが同期キューは、1つのタスクのみを持つことができ、すぐに実行されます参加します
パブリック 静的ExecutorServiceのnewCachedThreadPool(){ 戻り 新しい ThreadPoolExecutor(0 は、Integer.MAX_VALUE、 60L 、TimeUnit.SECONDS、 新しい SynchronousQueue <Runnableを> ()); }
4、ThreadPoolExecutor他のメンバー
前のReentrantLockのを参照してください可能性があるが書いたロック--lock Javaとの同期で ReentrantLockの原則の具体的な実現に落ちました;
AQSについて基準部がされる前に言ったJavaキュー同期AQSに、また、AQS分析上の特定の実装の原則に言及。
キューの状態についての知識は書くために戻って参照することがコラボレーションのJavaの条件スレッドでコラボレーションのJavaのスレッド条件に関する原則の実現に来ます;
// 新しいワーカースレッドのアトミック動作ワーカー制御するための排他的ロック プライベート 最終 ReentrantLockのmainLock =の新しい新しいReentrantLockののを(); //は、スレッドの作業セット、及び作業者がインターフェースAQS、Runnableインタフェースを継承し、オブジェクトがスレッド特定の処理タスクであります / / 労働者はAQSを達成し、状態= 0が取得されていないロックの現在の状態を表す彼のシンプルな非リエントラント排他的ロックを実現するために、状態= 1は、ロックが取得されていることを示し、 // 状態は= -1デフォルトの状態は時に仕事を作成していることを示し、 runWorker前に中断される方法の動作を防止するために設けられて作成時の状態= -1 プライベート 最終 HashSetの<労働>労働者は= 新しい新しい HashSetの<ワーカー> (); // 終了条件対応するロック待ち行列は、awaitTerminationスレッド呼び出しが使用されるときことストアは、スレッドブロックされた プライベート 決勝を条件条件終了= mainLock.newConditionのために();
第三に、ソースコード解析
1、公共ボイドを実行(Runnableをコマンド)の実装方法
エグゼキュータ方式の役割は、スレッドプールタスクコマンドの実行に提出することで、単に以下の図面を被験者読み取ることができ、ユーザーは要素を生成するために生産者にスレッドプール同等にタスクを追加するとき、ThreadPoolExecutor実装は、生産者 - 消費者モデルに類似しています、労働者は労働者に直接タスクを実行したり、消費者の要素の消費量に相当するタスクキューからタスクを取得します。
1つの 公共 ボイド(Runnableをコマンド)を実行{ 2 //(1)タスクがnull、nullであるかどうかを最初にチェックがスロー、または以下のステップを行う 3。 IF(コマンド== NULL ) 4。 スロー 新しい新規のNullPointerException(); 5 / (2)/ CTLは、スレッドプールの現在の状態の値と、スレッドプール内のスレッドの数が含まれてい 6。 INT C = ctl.get(); 7 //(3)workerCountOf方法、すなわち、現在のスレッドのプールを取得し、低29を得ることですスレッドの数は、実行するために新しいスレッドを開くために、corePoolSize未満である 8。 IF(workerCountOf(C)< corePoolSize){ 9。 IF(addWorker(コマンド、真の)) 10 リターン; 11 = Cのctl.get(); 12である } 13は、 //(4)スレッドプールは、状態を実行している場合、タスクはブロッキングキューに追加された 14 IF(isRunning(C)&& workQueue.offer(コマンド)){ 15 //( 4-1)二次検査、CTLの値を取得 16 int型 =で再チェックをctl.get(); 17 //(4-2)現在のスレッド・プールは、RUNNING状態から外れていない場合は、キューからジョブを削除し、戦略を実行することを拒否 18 のIF(isRunning(で再確認してください)&&!削除(コマンド)) 19を 拒否(コマンド); 20 //(4-3)スレッドプールが空の場合はそうでない場合は、スレッドの追加 21を 他の IF(workerCountOf(で再確認してください)== 0 ) 22 addWorker(ヌル、偽); 23 } 24 //(5)キューがいっぱいの場合は、新しいスレッドが失敗した場合は、新しいスレッドの実装上のポリシー拒否 25を 他 のIF(addWorker(コマンド,! 偽)) 26は (コマンドを拒否); 27 }
私たちは、デジタルマーカーの分析によると、上記のコードの実行の流れを見てみましょう。
ステップ(3)は、コア未満スレッドの数、コアスレッドが内部ワーカーにタスクを追加する場合は、プール内のスレッドの現在の数が、corePoolSize未満であるかを判断します。
プール内のスレッドの現在の数は、実装(4)上のスレッドのコアの数よりも大きい場合。(4)最初にこの状態で、あなたは状態は、スレッドプールがすでに非実行状態にしながら、非RUNNING状態であってもよいので、スレッドプールがあるかを決定するために必要とされるタスクキューにタスクを追加した場合、現在のスレッド・プールは、RUNNING状態であると判断新しいタスクを放棄する必要があります。
あなたが追加したい場合は、タスクキューのタスクがタスクキューにタスクを追加した後、スレッドプールのステータスが変更されている可能性があるため、二次キャリブレーションの必要性、成功しているので、現在のスレッドプールが実行されていない場合、二次検査が必要です状態、タスクがタスクキューから削除し、その後の戦略を実行することを拒否される必要がある、二次照合が成功した場合、スレッドは、スレッドプールでない場合、現在のスレッド・プールが空であるかどうかを決定するために再び4-3のコードを実行は、その後、空であります私たちは、新しいスレッドを作成する必要があります。
上記工程(4)を作成する追加タスクが失敗した場合は、キューが満杯である場合、(5)場合、再オープンする新しいスレッドを(すなわち、それらのスレッドは、コアスレッドないアナログ画像thread3とthread4、上記)のタスクを実行しようとしスレッドプール内のスレッドの現在の数は、彼らが新しいスレッドを開くことができないことを、スレッドの最大数maximumPoolSizeより大きくなっています。それはいっぱいで、タスクキューがいっぱいになって、あなたが拒否戦略を実行する必要がスレッドプールに属します。