线程池状态和使用注意点
線程池的狀態(tài)
- RUNNING:接收新的任務(wù),執(zhí)行阻塞隊列中的任務(wù)
- SHUTDOWN:不接受新任務(wù),但是仍然可以處理阻塞隊列中的任務(wù)
- STOP:不接受新任務(wù),不處理阻塞隊列中的任務(wù),中斷正在處理的任務(wù)
- TIDYING:所有任務(wù)已終止,workerCount(工作線程數(shù)等于0),進(jìn)入TIDYING狀態(tài)將會執(zhí)行terminated()方法
- TERMINATED:terminated()方法執(zhí)行完成后進(jìn)入TERMINATED狀態(tài)
線程池狀態(tài)轉(zhuǎn)換如下:
-
RUNNING:能接受新提交的任務(wù),并且也能處理阻塞隊列中的任務(wù);
-
SHUTDOWN:關(guān)閉狀態(tài),不再接受新提交的任務(wù),但卻可以繼續(xù)處理阻塞隊列中已保存的任務(wù)。
-
STOP:不能接受新任務(wù),也不處理隊列中的任務(wù),會中斷正在處理任務(wù)的線程。在線程池處于 RUNNING 或 SHUTDOWN 狀態(tài)時,調(diào)用shutdownNow() 方法會使線程池進(jìn)入到該狀態(tài);
-
TIDYING:如果所有的任務(wù)都已終止了,workerCount (有效線程數(shù)) 為0,線程池進(jìn)入該狀態(tài)后會調(diào)用 terminated() 方法進(jìn)入TERMINATED 狀態(tài)。
-
TERMINATED:在terminated()方法執(zhí)行完后進(jìn)入該狀態(tài)。?
各運(yùn)行狀態(tài)的表示方式:
// runState is stored in the high-order bits private static final int RUNNING = -1 << COUNT_BITS; private static final int SHUTDOWN = 0 << COUNT_BITS; private static final int STOP = 1 << COUNT_BITS; private static final int TIDYING = 2 << COUNT_BITS; private static final int TERMINATED = 3 << COUNT_BITS; //原子變量 private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));public void execute(Runnable command) {//判斷提交的Runnable 任務(wù),如果為null,則報NullPointerExceptionif (command == null)throw new NullPointerException(); int c = ctl.get();//判斷當(dāng)前線程數(shù)是否小于核心線程數(shù),如果小于,那就調(diào)用addWorker方法新增一個Worker,也可以理解成一個線程if (workerCountOf(c) < corePoolSize) {//addWorker這個方法主要要做的事就是執(zhí)行command,同時第二個參數(shù)決定以哪個界限來進(jìn)行是否新增線程的判斷,傳入true則代表以核心線程數(shù)為判斷條件if (addWorker(command, true))return;c = ctl.get();}//走到這步邏輯,則說明線程數(shù)大于等于核心線程數(shù),或者addWorker方法調(diào)用失敗了,這時就判斷線程池是否是Running狀態(tài),如果是就調(diào)用offer方法提交線程任務(wù)到任務(wù)隊列中if (isRunning(c) && workQueue.offer(command)) {int recheck = ctl.get();//如果線程池狀態(tài)不是Running,說明線程池已經(jīng)被關(guān)閉,這時就移除新提交到隊列中的任務(wù)if (! isRunning(recheck) && remove(command))//執(zhí)行拒絕策略reject(command);//檢查下當(dāng)前線程數(shù)是不是為0,為0的話就沒有線程執(zhí)行任務(wù)了 else if (workerCountOf(recheck) == 0)//所以就通過addWorker新建一個線程addWorker(null, false);}//走到這步邏輯,要么是線程池狀態(tài)不是Running,說明已經(jīng)關(guān)閉了,要么就是添加任務(wù)進(jìn)任務(wù)隊列時失敗了,說明任務(wù)隊列滿了,這時候就該添加最大線程數(shù)了,傳入false則代表以最大線程數(shù)為判斷條件else if (!addWorker(command, false))//以上addWorker方法如果返回結(jié)果是false,就會執(zhí)行拒絕策略了reject(command);}內(nèi)置的四種線程池
- SingleThreadExecutor:單線程化的Executor
- FiexedThreadPool:固定數(shù)目線程的線程池(隊列數(shù)沒有限制)
- CachedThreadPool:可緩存的線程池(線程數(shù)沒有限制)
- ScheduledThreadPool:支持定時及周期性的任務(wù)執(zhí)行的線程池,多數(shù)情況下可用來替代Timer類
這4個線程池都可能存在問題,不建議直接使用,建議使用自定義參數(shù)的線程池
線程池中重要的配置
- corePoolSize?: 核心線程數(shù)量
- workQueue?: 等待隊列
- maximumPoolSize?: 最大線程數(shù)量
提交任務(wù)時,判斷的順序為?corePoolSize --> workQueue -->maximumPoolSize
當(dāng)線程數(shù)小于核心線程數(shù)時,創(chuàng)建核心線程
當(dāng)線程大于等于核心線程數(shù),且任務(wù)隊列未滿時,將任務(wù)放入隊列
當(dāng)線程數(shù)大于核心線程數(shù),且任務(wù)隊列已滿時,檢查最大線程數(shù)是否已滿,若未滿,創(chuàng)建非核心線程,若滿,根據(jù)拒絕策略拋出異常拒絕任務(wù)。
?
拒絕策略—RejectedExecutionHandler
- AbortPolicy?: 直接拋出異常,這是默認(rèn)策略
- CallerRunsPolicy?: 用調(diào)用者所在線程來執(zhí)行任務(wù)
- DiscardOldestPolicy?: 丟棄阻塞隊列中最靠前的任務(wù),并執(zhí)行當(dāng)前任務(wù)
- DiscardPolicy?: 直接丟棄任務(wù)
?
遇到的坑!!!
- 任務(wù)提交后長時間沒有執(zhí)行
1.任務(wù)進(jìn)入了隊列,線程還在執(zhí)行之前的任務(wù)。提交的任務(wù)還在排隊等待執(zhí)行中
- 線程執(zhí)行任務(wù)中無故消失
? ? ? ? ? 1.? 線程拒絕策略配置為CallerRunsPolicy、DiscardOldestPolicy、DiscardPolicy時 ,線程池滿了不會拋出異常。建議將拒絕策略配置為AbortPolicy
? ? ? ? ? 2.? 一般情況下,代碼只會去捕捉Exception,如果拋出Error(比如內(nèi)存溢出)則會導(dǎo)致線程退出,而異常信息又沒有拿到。最佳的解決辦法是給線程池設(shè)置UncaughtExceptionHandler
?
總結(jié)
以上是生活随笔為你收集整理的线程池状态和使用注意点的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Executor家族的辨析
- 下一篇: ThreadLocal的两种用法