線程池的特點,優(yōu)勢,創(chuàng)建
特點
用線程池控制運行線程的數(shù)量, 將處理中的線程任務(wù)放入隊列, 線程創(chuàng)建后啟動這些任務(wù), 當(dāng)線程超出最大數(shù)量的時候, 進入隊列排隊, 等其他線程執(zhí)行完畢,再從隊列中取出任務(wù)執(zhí)行.
優(yōu)勢
- 降低資源消耗, 重復(fù)利用線程, 降低線程創(chuàng)建與銷毀的消耗
- 提供響應(yīng)速度, 當(dāng)任務(wù)到達時, 任務(wù)不需要等待線程創(chuàng)建, 可以立即執(zhí)行
- 提高線程管理, 統(tǒng)一分配, 調(diào)優(yōu), 監(jiān)控
- 合理使用線程池可以防止處理OOM問題
創(chuàng)建
ThreadPoolExecutors線程池7大參數(shù)
- corePoolSize: 線程池中的核心線程數(shù)
- maximumPoolSize: 最大線程數(shù), 必須大于1
- keepAliveTime: 多余的空閑時間
- unit: keepAliveTime單位
- queueCapacity: 任務(wù)隊列
- threadFactory: 線程池中線程工廠
- rejectedExecutionHandler: 拒絕策略
ThreadPoolExecutors線程池4種拒絕策略
- AbortPolicy(默認): 直接拋異常
- CallerRunsPolicy: "調(diào)用者運行"一種調(diào)試機制, 將任務(wù)返回調(diào)用者
- DiscardOldestPolicy: 拋棄隊列中等待最久的任務(wù)
- DiscardPolicy: 直接丟棄任務(wù)
ThreadPoolExector線程池原理分析
public class ThreadPoolExecutorTest {
private static ThreadPoolExecutor executor =
new ThreadPoolExecutor(
2, // 核心線程數(shù)2
5, // 最大線程數(shù)5
4,
TimeUnit.MILLISECONDS,
new ArrayBlockingQueue<Runnable>(4)); // 隊列數(shù)4
public static void main(String[] args) throws InterruptedException {
for (int i = 1; i < 15; i++) {
final String b = String.valueOf(i);
TimeUnit.MILLISECONDS.sleep(100);
executor.execute(() -> {
System.out.println(Thread.currentThread().getName() + ": " + b);
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
TimeUnit.SECONDS.sleep(20);
}
}
線程池合理配置線程數(shù)
1)根據(jù)幾個值來決定
(1) tasks: 每秒的任務(wù)數(shù), 假設(shè)100 ~ 1000
(2) taskcost: 每個任務(wù)花費時間: 假設(shè)0.1s
(3) responsetime: 系統(tǒng)允許最大響應(yīng)時間, 假設(shè)1s
2)根據(jù)8020定律, corePoolSize計算:
任何一組東西中茎活,最重要的只占其中一小部分,約20%琢唾,其余80%盡管是多數(shù)载荔,卻是次要的,因此又稱二八定律
corePoolSize = tasks* taskcout = (100 ~ 1000) * 0.1 = 10 ~ 100
8020定律, 核心線程數(shù)為20
3)queueCapacity計算:
任務(wù)隊列的長度要根據(jù)核心線程數(shù)慧耍,以及系統(tǒng)對任務(wù)響應(yīng)時間的要求有關(guān)身辨。隊列長度可以設(shè)置為
queueCapacity = corePoolSize / taskcost * responsetime = 20 / 0.1 * 1 = 200
注: 若將隊列長度設(shè)置為Integer.MAX_VALUE,將會導(dǎo)致線程數(shù)量永遠為corePoolSize芍碧,再也不會增加煌珊,當(dāng)任務(wù)數(shù)量陡增時,任務(wù)響應(yīng)時間也將隨之陡增
4)maxPoolSize計算:
當(dāng)系統(tǒng)負載達到最大值時泌豆,核心線程數(shù)已無法按時處理完所有任務(wù)定庵,這時就需要增加線程
maxPoolSize = (max(sasks) - queueCapacity) * taskcost = (1000 -200) * 0.1 = 80
- rejectedExecutionHandler:根據(jù)具體情況來決定,任務(wù)不重要可丟棄,任務(wù)重要則要利用一些緩沖機制來處理
6)keepAliveTime和unit采用默認通常能滿足
合理創(chuàng)建線程池
ThreadPoolExecutor executor =
new ThreadPoolExecutor(
20, //核心線程數(shù)
80, //最大線程數(shù)
1, // 多余的空閑時間
TimeUnit.SECONDS, //多余的空閑時間單位
new ArrayBlockingQueue<>(200) //隊列長度
,new ThreadFactoryBuilder().setNameFormat("xx-pool-%d").build(), //創(chuàng)建
new ThreadPoolExecutor.DiscardPolicy() //處理策略
);