--------------------------------------
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狀態後通知正在等待線程池終止的線程...
--------------------------------------