スレッドプールのクラス図
エグゼキュータ==> ExcutorService ==> AbstractExecutorService ==> ThreadPoolExecutor分析します。
- URL継承階層の上には、インターフェースのトップレベルは、スレッドプールエグゼキュータで、このインタフェースは、唯一の方法ボイドは(Runnableをコマンド)を実行しています
- エグゼキュータ継承ExecutorServiceのは、いくつかの主要な新しい方法(Runnableを(コーラブル))、シャットダウン、shutdownNowの提出など
- AbstractExecutorServiceの実装方法上記いくつかのインタフェースExecutorServiceの。
- ThreadPoolExecutor継承AbstractExecutorService、主要な方法のいくつかを達成するために、スレッドプール(Runnableを)を実行します。
AbstractExecutorService
次のようにAbstractExecutorServiceは、方法書を提出達成しました:
(呼び出し可能タスク)提出方法
- パブリック<T>将来<T>提出する(呼び出し可能<T>タスク){
- (タスク== nullは))(新しいNullPointerExceptionが投げた場合。
- RunnableFuture <T> ftask = newTaskFor(タスク)。
- (ftask)を実行します。
- ftask返します。
- }
newTaskFor(呼び出し可能呼び出し可能)方法
- 保護<T> RunnableFuture <T> newTaskFor(呼び出し可能<T>呼び出し可能){
- <T>(呼び出し可能)新しいFutureTaskを返します。
- }
FutureTask上記RunnableFutureインタフェースを実現し、RunnableFutureはRunnableをと今後インターフェースを継承します。ボイドランのみ、Runnableインタフェース方法、今後のインターフェイスは(boolean)を取り消し、V得る()、V得る(長いタイムアウト、TimeUnitでユニット)、ブールisCancelled()、ブールisDone()メソッド。
ThreadPoolExecutor
次に実行するAbstractExecutorService.submitメソッド呼び出し(ftask)上に、これはThreadPoolExecutorを実行することです。その後、我々は、開始点として、メソッドを実行するために分析することがあります。
実行
- 公共ボイドは、{(Runnableをコマンド)を実行します
- (コマンド== null)の場合
- 新しいNullPointerExceptionがスロー();
- INT C = ctl.get()。
- IF(workerCountOf(C)<corePoolSize){
- もし(addWorker(コマンド、真))
- リターン;
- C = ctl.get()。
- }
- IF(isRunning(C)&& workQueue.offer(コマンド)){
- INT再検査= ctl.get()。
- (もし!isRunning(再検査)&&削除(コマンド))
- (コマンド)を拒絶します。
- それ以外の場合(workerCountOf(再検査)== 0)
- addWorker(ヌル、偽);
- }
- それ以外の場合(!addWorker(コマンド、偽))
- (コマンド)を拒絶します。
- }
- まず、チェックワーカースレッドの現在の数が少なくcorePoolSizeよりも、このタスク(commadn)を処理するために労働者を追加し、10未満の場合には、成功したが返されたタスクを追加しています。
- スレッドが実行中の状態のままであり、非動作している場合、正常キュー、スレッドプールの状態を再確認し、スレッドプールに追加タスクは、キューからジョブを削除した場合、呼び出しの成功は拒否し、ポリシーに従って行うためにここに拒否し、現在の場合ワーカースレッドの数が0である場合、作業者を追加(ここで注意することは、addWorker(NULL、偽)、最初のパラメータと上記addWorkerと同じではありません)
- あなたが追加した場合、作業者はまた、実行方法を拒否することができません。
addWorker
- プライベートブールaddWorker(RunnableをfirstTask、ブールコア){
- リトライ:
- にとって (;;) {
- INT C = ctl.get()。
- INT RS = runStateOf(C);
- //必要に応じて、キューが空にのみかどうかを確認してください。
- もし(RS> = SHUTDOWN &&
- !(RS == SHUTDOWN &&
- firstTask == nullの&&
- !workQueue.isEmpty()))
- falseを返します。
- にとって (;;) {
- INT WC = workerCountOf(C);
- (WC> = CAPACITYもし||
- WC> =(コアcorePoolSize:?maximumPoolSize))
- falseを返します。
- もし(compareAndIncrementWorkerCount(c)参照)
- 再試行を破ります。
- C = ctl.get()。//再読み込みCTL
- もし(runStateOf(C)!= RS)
- 再試行を続けます。
- //他のCASはworkerCount変化により失敗しました。内側のループを再試行してください
- }
- }
- ブールworkerStarted =偽;
- ブールworkerAdded =偽;
- = NULL Wワーカー。
- {試します
- W =新しいワーカー(firstTask)。
- 最後のスレッドT = w.thread。
- もし(T!= NULL){
- 最終ReentrantLockのmainLock = this.mainLock。
- mainLock.lock();
- {試します
- //再確認ロックを保持しながら。
- ThreadFactory故障の場合、または//バックアウト
- //ロックを取得する前にシャットダウンします。
- INT RS = runStateOf(ctl.get())。
- (RS <SHUTDOWNもし||
- (RS == SHUTDOWN && firstTask == NULL)){
- もし(t.isAlive())//事前チェックtが始動可能であること
- 新しいないIllegalThreadStateExceptionを投げます();
- (W)workers.add。
- INT S = workers.size()。
- もし(S> largestPoolSize)
- largestPoolSize = S;
- =真workerAdded。
- }
- } 最後に {
- mainLock.unlock();
- }
- {(workerAdded)場合
- t.start();
- =真workerStarted。
- }
- }
- } 最後に {
- (もし!workerStarted)
- (W)addWorkerFailed。
- }
- workerStartedを返します。
- }
(1)意思決定ロジックが複雑で、我々は最初に見
- もし(RS> = SHUTDOWN &&
- !(RS == SHUTDOWN &&
- firstTask == nullの&&
- !workQueue.isEmpty()))
- falseを返します。
決意の条件は明らかにトゥーレ、直接returnfalseであれば、現在の状態は、SHUTDOWNよりも大きい場合。判定条件が偽の場合SHUTDOWN未満の現在の状態は、その後、ダウンした場合場合(スレッドプールRUNNING状態は、よく理解)(まあ理解し、スレッドプールは、新しいワーカーAを追加していない確かにクローズされる)と等しいの現在の状態SHUTDOWN:firstTaskキュー仕事がnullに等しいとタスクを持っている場合、それはダウンを実行していきますが、条件がfalseの場合、コードが戻らないと判断され、nullに等しくされていない、またはfirstTask作業キューが空の場合、条件が真であると判断され、falseを返します(最初のヌルと等しい場合イェジンハオは、そのため。我々は、スレッドプールは、もはや新しいタスクを受け入れているSHUTDOWN状態を知っていませんが、タスクは作業キューやジョブを完了するためにされている、このことを理解し、作業キューは、タスクを持っていますが、またし続けます起工。反対の場合は、それがダウンして行くことはありません)(2)ワーカースレッドの現在の数を決定するために
- にとって (;;) {
- INT WC = workerCountOf(C);
- (WC> = CAPACITYもし||
- WC> =(コアcorePoolSize:?maximumPoolSize))
- falseを返します。
- もし(compareAndIncrementWorkerCount(c)参照)
- 再試行を破ります。
- C = ctl.get()。//再読み込みCTL
- もし(runStateOf(C)!= RS)
- 再試行を続けます。
- //他のCASはworkerCount変化により失敗しました。内側のループを再試行してください
- }
ワーカースレッドの現在の数は制限パラメータは、スレッドプールの設定を超えていない、労働者を追加するにはCASの使用は、ループのための外側のうち、ダウンを実行し続けます。それ以外の場合はfalseを返し、労働者が失敗した追加。(3)上記工程12の完了後、実行する新しいワーカー(firstTask)、tはw.threadスレッドプールを=スレッドと再び状態をチェックが、有効であれば、現在の作業スレッドプールワーカーHashSetのに加え、実行T .start。タスクを実行するために、サブスレッドを開く前に、この時間。
サブスレッドのrunメソッド
通話t.start上記のステップ3は、実行方法は、労働者で実行するサブスレッドを開きます。
- ます。public void実行(){
- runWorker(この);
- }
- 最終的な空隙runWorker(Wワーカー){
- スレッド重量=にThread.currentThread()。
- 実行可能なタスクはw.firstTaskを=。
- w.firstTask = NULL;
- w.unlock(); //割り込みを許可します
- ブールcompletedAbruptly =はtrue。
- {試します
- 一方、(タスク!= NULL ||(タスク= getTask())!= NULL){
- w.lock();
- //プールは、スレッドが中断されたことを確認、停止されている場合は、
- //そうでない場合は、確実にスレッドが中断されていません。この
- //に対処するために、第2のケースで再チェックが必要です
- // shutdownNowのレース割り込みをクリアしながら、
- もし((runStateAtLeast(ctl.get()、STOP)||
- (Thread.interrupted()&&
- runStateAtLeast(ctl.get()、STOP)))&&
- !wt.isInterrupted())
- wt.interrupt();
- {試します
- beforeExecute(WT、タスク)。
- Throwableをスロー= NULL;
- {試します
- task.run();
- }最後に {
- afterExecute(タスク、スロー)。
- }
- } 最後に {
- タスク= NULL;
- w.completedTasks ++;
- w.unlock();
- }
- }
- completedAbruptly = falseは、
- } 最後に {
- processWorkerExit(completedAbruptly、W)。
- }
- }
連続getTask()メソッド、ワークキューからの取得タスクを通じて労働者の上に、何のタスクが取得されていない場合、processWorkerExitメソッドが呼び出されます。
getTask()
- プライベートRunnableをgetTask(){
- ブールTIMEDOUT =偽; //最後のポーリング()タイムアウトしましたか?
- にとって (;;) {
- INT C = ctl.get()。
- INT RS = runStateOf(C);
- //必要に応じて、キューが空にのみかどうかを確認してください。
- IF(RS> = SHUTDOWN &&(RS> = STOP || workQueue.isEmpty())){
- decrementWorkerCount();
- ヌルを返します。
- }
- INT WC = workerCountOf(C);
- //カリングへの労働者の対象はいますか?
- ブールの時限= allowCoreThreadTimeOut || トイレ> corePoolSize。
- もし((WC> maximumPoolSize ||(時限式&& TIMEDOUT))
- &&(WC> 1 || workQueue.isEmpty())){
- もし(compareAndDecrementWorkerCount(c)参照)
- ヌルを返します。
- 継続する;
- }
- {試します
- RunnableをR =タイミング?
- workQueue.poll(keepAliveTimeが、TimeUnit.NANOSECONDS):
- workQueue.take();
- もし(R!= NULL)
- Rを返します。
- TIMEDOUTは真=。
- }キャッチ(InterruptedExceptionあるリトライ){
- TIMEDOUT = falseは、
- }
- }
- }
getTaskが無限ループ法のための方法であり、それは最初のスレッドプールの現在の状態を決定します
- IF(RS> = SHUTDOWN &&(RS> = STOP || workQueue.isEmpty())){
- decrementWorkerCount();
- ヌルを返します。
- }
この判断も当RS == SHUTDOWNは、ワークキューが空の場合、明らかにそれは直接はnullを返す必要があり、作業の前に1つのワーカーによって低減され、理解されています。(getTaskリターンヌルは、runWorker方法はHashSetのワーカーからprocessWorkerExit削除電流を呼び出し); RSは> SHUTDOWNより大きい(スレッドプールshutdownNowのこの方法に対応する、ワークキューは、タスクが実行されていない待機中の)場合、そうでない場合、スレッドプールに記載しましたランニング、ダウンを実行し続けます。次に、スレッドの最大数は、スレッドプールは、現在設定され、時間およびステータス行coreThreadワークキュー上で許可するかどうかは、リターンヌル保存一緒にスレッドのCAS番号で動作するかどうかを判定する。最後に、我々は作業キュー3ヘッド事業から次の作業に注意を取得したいです。
- RunnableをR =タイミング?
- workQueue.poll(keepAliveTimeが、TimeUnit.NANOSECONDS):
- workQueue.take();
トゥーレ(trueにallowCoreThreadTimeOutセット)にタイミングを合わせて、より多くの待機時間よりもまだワークキューR =ヌルからタスクを達成していない、でも、この時点で、それは以下workerCount corePoolSizeよりも起こす可能性がある場合は、現在の作業員も回収することができます。時限式はfalseが、メソッドをコールブロッキングは、ワークキューからタスクを取得する場合は、newFixedThreadPoolは常にワークキューが空の場合でも、閉じられたスレッドプールを表示せずに達成するように、ブロックするメソッドを呼び出しますが、また、ワーカースレッドの固定数を維持するために、 。
shutDown(shutDownNow)方法
- 公共の一覧<Runnableを> shutdownNowの(){
- 一覧<Runnableを>タスク。
- 最終ReentrantLockのmainLock = this.mainLock。
- mainLock.lock();
- {試します
- checkShutdownAccess();
- SHUTDOWNとして// shutDwonNow STOPとして、シャットダウン
- advanceRunState(STOP);(advanceRunState(SHUTDOWN);)
- interruptWorkers();(interruptIdleWorkers)
- // shutdownNowの特別な
- タスク= drainQueue();
- //シャットダウン特別ScheduledThreadPoolExecutorのコールバック
- onShutdown();
- } 最後に {
- mainLock.unlock();
- }
- tryTerminate();
- タスクを返します。
- }
シャットダウン及びshutDownnNow差法(コードレベル):
- shutdownNowの:advanceRunState(STOP)、interruptWorkersシャットダウン:advanceRunState(シャットダウン)、interruptIdleWorkers
- シャットダウンよりonShutdown();のScheduledThreadPoolExecutor onShutDown複製方法。
- shutdownNowの方法は、キュー未完了のタスクを動作します。
- interruptIdleWorkers
interruptIdleWorkers与interruptWorkers
(1)shutdownNowの
- プライベート無効interruptWorkers(){
- 最終ReentrantLockのmainLock = this.mainLock。
- mainLock.lock();
- {試します
- (:労働者ワット労働者)のために
- w.interruptIfStarted();
- } 最後に {
- mainLock.unlock();
- }
- }
明らかに、これは中断され、すべてのスレッド(2)シャットダウンされます
- プライベート無効interruptIdleWorkers(ブール天然記念物){
- 最終ReentrantLockのmainLock = this.mainLock。
- mainLock.lock();
- {試します
- {(作業者Wワーカー)のために
- トン= w.threadスレッド。
- (もし!t.isInterrupted()&& w.tryLock()){
- {試します
- t.interrupt();
- }キャッチ(SecurityExceptionが無視){
- } 最後に {
- w.unlock();
- }
- }
- もし(天然記念物)
- ブレーク;
- }
- } 最後に {
- mainLock.unlock();
- }
- }
パラメータを天然記念物に注意してください、これが唯一の内部コールtryTerminate()メソッド呼び出しのinterruptIdleWorkers(真)に、それ以外の場合は、その停止方法のために、interruptIdleWorkers(偽)であるが、すべてが中断スレッドされていない破るしようとしています。この方法は、次に(2)上記3)tryTerminate tryTerminate方法になります
- 最終的な空隙tryTerminate(){
- にとって (;;) {
- INT C = ctl.get()。
- もし(isRunning(C)||
- runStateAtLeast(C、片付け)||
- (runStateOf(C)== SHUTDOWN &&!workQueue.isEmpty()))
- リターン;
- 終了する資格(workerCountOf(C)!= 0){//もし
- interruptIdleWorkers(ONLY_ONE)。
- リターン;
- }
- 最終ReentrantLockのmainLock = this.mainLock。
- mainLock.lock();
- {試します
- IF(ctl.compareAndSet(C、ctlOf(片付け、0))){
- {試します
- )(終了。
- } 最後に {
- ctl.set(ctlOf(TERMINATED、0));
- termination.signalAll();
- }
- リターン;
- }
- } 最後に {
- mainLock.unlock();
- }
- 失敗したCASに//他の再試行
- }
- }
上記のコードから分かるようにワーカースレッドの数がスレッドプールの状態がシャットダウンされた場合、空の、ワークキュースレッドプールは0又はSTOP状態、ワーカースレッド0の数であり、スレッドプールは、最終的TERMINATED状態にあり、すべてのウェイクアップしますtermination.awaitNanos(nanos値)のコールawaitTermination()メソッドブロックはスレッドを覚ますしていないため。
- パブリックブールawaitTermination(長いタイムアウト、TimeUnitでユニット)
- InterruptedExceptionが{スロー
- 長いnanos値= unit.toNanos(タイムアウト)。
- 最終ReentrantLockのmainLock = this.mainLock。
- mainLock.lock();
- {試します
- にとって (;;) {
- もし(runStateAtLeast(ctl.get()、TERMINATED))
- trueを返します。
- IF(nanos値<= 0)
- falseを返します。
- nanos値= termination.awaitNanos(nanos値)。
- }
- } 最後に {
- mainLock.unlock();
- }
- }
方法上記TryTerminate、addWorkerFailed()、processWorkerExit()、シャットダウン()、shutdownNowの()、削除(Runnableをタスク)メソッドが呼び出さにします。
スレッドプールを説明するための5つの状態
スレッドプールの上記頻繁に実行されている状態、ここでは簡単な説明。
- プライベート静的最終int型のRUNNING = -1 << COUNT_BITS。
- プライベート静的最終int型のSHUTDOWN = 0 << COUNT_BITS。
- プライベート静的最終int型のSTOP = 1 << COUNT_BITS。
- プライベート静的最終int型の片付け= 2 << COUNT_BITS。
- = 3 << COUNT_BITS TERMINATEDプライベート静的最終int型。
状態の定義
- RUNNING:新しいタスクを、ワークキュー内のタスクを処理します。
- SHUTDOWN:新しいタスクを受け入れませんが、タスクを完了していきますワークキュー
- STOP:すべての実行中のタスクを打破しようと、新しいタスクがワークキュー未完のタスクを扱いません同意しません
- 片付け:すべてのタスクが完了した、ワーカースレッドの数は、スレッドプールの状態が片付けが終わる()メソッドを呼び出しますなり、0です。
- TERMINATED:終了()メソッドが完了しました
5つの状態変換
- RUNNING - > SHUTDOWN:コールシャットダウン()メソッドは、おそらく暗黙のファイナライズ中()メソッド
- (RUNNINGまたはSHUTDOWN) - > STOP:コールshutdownNowの()メソッド
- SHUTDOWN - >片付け:ワークキューとプールが空であります
- STOP - >片付け:プールが空であります
- 片付け - > TERMINATED:終了()方法完成