相關問題
1揪利、工作流程是怎么樣的植锉。
2泥栖、核心參數(shù)礼烈。
3弧满、任務結(jié)束之后如何恢復到核心線程數(shù)。
4此熬、線程池運行時有一個線程報錯了會怎么樣谱秽。
5、如何合理設置核心線程數(shù)的大小
6摹迷、不同子線程之間怎么傳遞數(shù)據(jù)
7、5個核心線程數(shù)郊供,30個任務隊列峡碉,20個最大線程數(shù),200s存活時間驮审,一個for循環(huán)加入20個任務鲫寄,
這個時候線程池中有多少個。
1疯淫、工作流程是怎么樣的地来。
execute方法
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
/*
* Proceed in 3 steps:
* 1.如果運行的線程少于核心線程數(shù),嘗試新建一個線程作為第一個任務熙掺。
*
* 2. 如果有任務可以成功排隊未斑,那就加入隊列
*
* 3. 如果無法加入隊列,那么嘗試添加一個新線程币绩。
* 要是失敗了就知道被關閉或包和了蜡秽,因此拒絕這項任務
*/
int c = ctl.get();
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command))
reject(command);
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
else if (!addWorker(command, false))
reject(command);
}
2、核心參數(shù)缆镣。如何合理設置核心線程數(shù)的大小
最?線程數(shù)maximumPoolSize
-
核?線程數(shù)corePoolSize
任務隊列的長度要根據(jù)核心線程數(shù)芽突,以及系統(tǒng)對任務響應時間的要求有關。隊列長度可以設置為 所有核心線程每秒處理任務數(shù) * 每個任務響應時間 = 每秒任務總響應時間 董瞻,即(corePoolSizethreadtasks)responsetime: (2010)2=400寞蚌,即隊列長度可設置為400。
-
活躍時間keepAliveTime
當負載降低時钠糊,可減少線程數(shù)量挟秤,當線程的空閑時間超過keepAliveTime,會自動釋放線程資源眠蚂。默認情況下線程池停止多余的線程并最少會保持corePoolSize個線程煞聪。
-
阻塞隊列workQueue
BlockingQueue workQueue = null; workQueue = new ArrayBlockingQueue<>(5);//基于數(shù)組的先進先出隊列,有界 workQueue = new LinkedBlockingQueue<>();//基于鏈表的先進先出隊列逝慧,無界 workQueue = new SynchronousQueue<>();//無緩沖的等待隊列昔脯,無界
拒絕策略RejectedExecutionHandler
可繼承后進行自定義啄糙。
提供的拒絕策略有:
- AbortPolicy:直接丟棄任務,拋出異常云稚,這是默認策略
- CallerRunsPolicy:只?調(diào)?者所在的線程來處理任務
- DiscardOldestPolicy:丟棄等待隊列中最舊的任務隧饼,并執(zhí)?當前任務
- DiscardPolicy:直接丟棄任務,也不拋出異常
- allowCoreThreadTimeout
默認情況下核心線程不會退出静陈,可通過將該參數(shù)設置為true燕雁,讓核心線程也退出。
一般說來鲸拥,大家認為線程池的大小經(jīng)驗值應該這樣設置:(其中N為CPU的個數(shù))
- 如果是CPU密集型應用拐格,則線程池大小設置為N+1
- 如果是IO密集型應用,則線程池大小設置為2N+1
3刑赶、任務結(jié)束之后如何恢復到核心線程數(shù)/線程池中多余的線程是如何回收的捏浊?
什么時候回收線程?
ThreadPoolExecutor回收工作線程撞叨,一條線程getTask()返回null金踪,就會被回收。
分為兩種情況
一牵敷、未調(diào)用shutdown() 胡岔,RUNNING狀態(tài)下全部任務執(zhí)行完成的場景
線程數(shù)量大于corePoolSize,線程超時阻塞枷餐,超時喚醒后CAS減少工作線程數(shù)靶瘸,如果CAS成功,返回null尖淘,線程回收奕锌。否則進入下一次循環(huán)。當工作者線程數(shù)量小于等于corePoolSize村生,就可以一直阻塞了惊暴。
二、調(diào)用shutdown() 趁桃,全部任務執(zhí)行完成的場景
2.1 所有線程都在阻塞
中斷喚醒辽话,進入循環(huán),都符合第一個if判斷條件卫病,都返回null油啤,所有線程回收。
2.2 任務還沒有完全執(zhí)行完
至少會有一條線程被回收蟀苛。在processWorkerExit(Worker w, boolean completedAbruptly)方法里會調(diào)用tryTerminate()益咬,向任意空閑線程發(fā)出中斷信號。所有被阻塞的線程帜平,最終都會被一個個喚醒幽告,回收梅鹦。
如何被回收的。
private void processWorkerExit(Worker w, boolean completedAbruptly) {
if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted
decrementWorkerCount();
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
completedTaskCount += w.completedTasks;
//這里就是回收線程的主要操作了冗锁,移除線程池對該線程的引用齐唆,使其可以被JVM正常地回收
workers.remove(w);
} finally {
mainLock.unlock();
}
tryTerminate();
int c = ctl.get();
if (runStateLessThan(c, STOP)) {
if (!completedAbruptly) {
int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
if (min == 0 && ! workQueue.isEmpty())
min = 1;
if (workerCountOf(c) >= min)
return; // replacement not needed
}
addWorker(null, false);
}
}
在runWorker()
方法中被執(zhí)行
ThreadPoolExecutor是怎么回收線程的:
https://juejin.cn/post/6922069411981426702
4、線程池運行時有一個線程報錯了會怎么樣冻河。
當一個線程池里面的線程異常后:
1箍邮、當執(zhí)行方式是execute時,可以看到堆棧異常的輸出
ThreadPoolExecutor.runWorker()方法中,task.run()叨叙,即執(zhí)行我們的方法锭弊,如果異常的話會throw x;所以可以看到異常。
2擂错、當執(zhí)行方式是submit時,堆棧異常沒有輸出廷蓉。但是調(diào)用Future.get()方法時,可以捕獲到異常
ThreadPoolExecutor.runWorker()方法中马昙,task.run(),其實還會繼續(xù)執(zhí)行FutureTask.run()方法刹悴,再在此方法中c.call()調(diào)用我們的方法行楞,如果報錯是setException(),并沒有拋出異常土匀。當我們?nèi)et()時子房,會將異常拋出。
3就轧、不會影響線程池里面其他線程的正常執(zhí)行
4证杭、線程池會把這個線程移除掉,并創(chuàng)建一個新的線程放到線程池中
當線程異常妒御,會調(diào)用ThreadPoolExecutor.runWorker()方法最后面的finally中的processWorkerExit()解愤,會將此線程remove,并重新addworker()一個線程乎莉。
execute
的入?yún)⑹荝unnable送讲, 沒有返回值。任務通過execute
提交后就基本和主線程脫離關系了惋啃。
而submit
的入?yún)⒖梢允荂allable(也可以是Runnable)哼鬓,并且有返回值,返回的是一個Future
對象边灭,然后通過對象的get
方法獲取任務執(zhí)行的結(jié)果异希。
5、不同子線程之間怎么傳遞數(shù)據(jù)
6绒瘦、5個核心線程數(shù)称簿,30個任務隊列扣癣,20個最大線程數(shù),200s存活時間予跌,一個for循環(huán)加入20個任務搏色,這個時候線程池中有多少個。
結(jié)合線程池的工作原理就能知道有5個活躍線程