concurrent包-線程池

來源:互聯網
上載者:User

--------------------------------------
0. threadPoolExecutor
--------------------------------------
   0. int runState
   表示線程池啟動並執行狀況分四個層級,RUNNING|SHUTDOWN|STOP|TERMINATED,啟動的時候為RUNNING,啟動後
   外界只能主動的將其設定成shutdown->SHUTDOWN,shutdown->STOP,當然這過程還做了其他的事...
--------------------------------------
   1. BlockingQueue<Runnable> workQueue
   阻塞隊列,外部線程往workQueue中添加runnable,其中添加的方式是非阻塞的,滿了就走其他的邏輯
   worker死迴圈到workQueue中取runnable來執行,而取的邏輯跟環境有關,分三種情況
   非阻塞的取,限時阻塞可中斷的取和永久阻塞可中斷的取...
   --------------------------------------
   2. long keepAliveTime
   上面提到的如果是限時阻塞取中等待的時間...
--------------------------------------
   3. boolean allowCoreThreadTimeOut
   上面提到的worker取任務三種模式,如果此為TRUE則會進入到限時阻塞
--------------------------------------
   4. int corePoolSize
   執行任務的worker的數目,如果目前啟動並執行worker超過這個數目則可能會導致任務加到workQueue中等
   worker空閑了以後來取再執行,故會有點不即時...
   --------------------------------------
   5. int maximumPoolSize
   執行任務的worker的最大數目,當目前啟動並執行worker超過corePoolSize且workQueue也滿了的話會添加新的
   worker來執行新加入的任務,如果worker超過了maximumPoolSize會拒絕這個任務...
--------------------------------------
   6. int poolSize -- 目前worker數目
--------------------------------------
   7. RejectedExecutionHandler handler
   對於被拒絕的runnable的處理邏輯
--------------------------------------
   8. ThreadFactory threadFactory
--------------------------------------
--------------------------------------
1. execute runnable
   --------------------------------------
   總體原則是對於runState不是RUNNING時添加進來的任務都會直接走reject流程
   在RUNNING狀態下提交進來的任務的處理大抵流程是
   ------------
   a. 如果目前workers數目小於corePoolSize則執行個體化一個worker,將此runnable作為此worker的第一個任務,
   啟動此背景工作執行緒
   ------------
   b. 如果目前workers數目大於等於corePoolSize則考慮將此runnable加入到workQueue中,調用的是來自Queue的
   offer函數故如果目前workQueue滿了的話會做如下操作:如果目前workers數目小於maximumPoolSize則執行個體化一
   個worker,將此runnable作為此worker的第一個任務,啟動此背景工作執行緒;如果workers數目已經超過maximumPoolSize
   而同時workQueue已經滿了則表示要放棄此runnable,走reject流程
   ------------
   c. 在b中workQueue還沒滿則將runnable加進去,緊接著判斷下目前健全狀態,如果不再是RUNNING或者目前workers
   數目變成了0(可能是先前啟動的線程都因為異常或者其他原因而退出了...)的話則要保證已經加入到workQueue的  
   runnable能夠被處理,其處理邏輯:如果目前runState不是RUNNING,且能將runnable從workQueue中移除,則走 
   reject流程;如果目前如果目前runState是RUNNING|SHUTDOWN且目前workers數目小於corePoolSize且workQueue中有
   任務則會執行個體化一個worker,啟動此背景工作執行緒
--------------------------------------
--------------------------------------
2. reject runnable 目前ThreadPoolExecutor提供了四種策略
--------------------------------------
   a. CallerRunsPolicy
   如果目前state為RUNNING則由提交任務的線程自己執行runnable.run 否則不予理睬...
--------------------------------------
   b. AbortPolicy
   直接拋出異常RejectedExecutionException...
--------------------------------------
   c. DiscardPolicy 什麼也不做...
   --------------------------------------
   d. DiscardOldestPolicy
   如果目前state為RUNNING則將workQueue最先提交的任務刪除,再走一遍execute runnable流程
   否則不予理睬...
   這個策略可以自己實現,提供給了ThreadPoolExecutor用來拿到ThreadPoolExecutor的環境做參考,
   同時runnable也提供給你了...
--------------------------------------
3. worker邏輯
   ---------------------
   Runnable task = firstTask
   while (task != null || (task = getTask()) != null) {
       runTask(task)
       task = null
   }
   workerDone(this)
   有些worker啟動起來的時候會給一個初始化任務,有些則是啟動起來以後直接到workQueue中
   去拿任務,worker就是一個不斷的到task中去拿任務再執行的過程
   getTask -> runTask -> getTask -> runTask這樣worker執行時間分為兩段,一是工作時間,
   一個是拿任務時間,這段時間可能有休眠時間故可中斷,而工作時間也可能因為未TPE代碼 
   引起的休眠。即getTask是不受worker內部鎖保護,而runTask是受內部搜保護的。故worker
   在getTask被掉interruptIfIdle時是會立即起效的,調interruptNow肯定是立即起效。而 
   在runTask被掉interruptIfIdle時無效,調interruptNow立即起效。
   當在執行任務過程中遇到運行時異常或者取不到任務了則會走worker退休流程
   ---------------------
   getTask邏輯
   如果runState為STOP|TERMINATED則直接返回null
   如果runState為SHUTDOWN則走Queue的poll去取任務,非阻塞的取
   如果runState為RUNNING則看如果目前worker資料大於corePoolSize或者allowCoreThreadTimeOut
   則限時取,否則永久阻塞的取,在取任務邏輯最後,如果沒有取到資料,則表示是不是需要關閉線程池裡面的一些線程了,
   當然這個worker是註定要關閉了,首先進行一些判斷
   如果runState >= SHUTDOWN | workQueue空了 | (逾時請求 && poolSize > corePoolSize)滿足的話
   則迭代線程池調用interruptIfIdle,這樣目前還在getTask上阻塞的線程就被喚醒了,然後退出
---------------------
   runTask邏輯
   啟動了內部鎖保護,在執行前如果runState如果是RUNNING|SHUTDOWN會吃掉worker的中斷標誌
   以免其影響任務的正常執行...
   調用runnable.run 運行時異常被吃掉了再被跑出去了,故運行時異常好處理好否則會導致一個worker的死亡...
   ---------------------
   內部鎖保護,先前很多地方提到內部鎖保護,這個要和TPE結合起來理解
   1. TPE.shutdown時會迭代線程池調用interruptIfIdle這樣在getTask上阻塞的線程就被喚醒了,然後退出
   2. TPE.shutdownNow時會迭代線程池調用interruptNow這樣在getTask上阻塞的線程就被喚醒了,
   然後退出,而正在執行任務的線程也被標記為中斷,如果有做等待或者IO會拋中斷異常,業務代
   碼便知道此線程池被掉關閉了...
   3. worker在getTask時如果取不到任務表示可能任務資源沒了,需要釋放線程池的空閑資源了...
--------------------------------------
4. shutdown邏輯
   如果runState小於SHUTDOWN則設定成SHUTDOWN,這點的影響是
   1. execute runnable時外部線程再新增工作進來可能會被拒絕走reject流程,如果碰巧任務加到
   workQueue中後標記為SHUTDOWN則會走其他邏輯,上面有提到...
   2. reject runnable很多策略都是只處理RUNNING的
   3. worker.getTask,在SHUTDOWN下worker進行非阻塞取任務...
   另外會迭代調用線程池的interruptIfIdle,消滅空閑線程
--------------------------------------
5. shutdownNow邏輯
   如果runState小於STOP則設定成STOP,這點的影響基本上和shutdown差不多,唯一的區別在於
   其迭代調用線程池的interruptIfNow,這點會影響業務代碼,如果有做可中斷的操作則會拋出
   中斷異常...
   在shutdown和shutdownNow最後,以及當個線程退休時
   都會去判斷下目前線程是否可以到TERMINATED狀態了,要進入TERMINATED必須目前worker為空白
   才有下面的邏輯:
   如果state小於STOP而且workQueue裡還有任務,則會執行個體化一個worker起來,並且state為RUNNING
   如果state為STOP|(SHUTDOWN且workQueue裡無任務)則可以TERMINATED狀態了
   在進入TERMINATED狀態後通知正在等待線程池終止的線程...
--------------------------------------

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.