線程池
線程池的好處:
- 降低資源的消耗
- 提高響應的速度
- 方便管理。
線程複用、可以控制最大併發數、管理線程
三大創建方法
ExecutorService threadPool = Executors.newSingleThreadExecutor();
// 單個線程ExecutorService threadPool = Executors.newFixedThreadPool(10);
// 創建一 個固定的線程池的大小ExecutorService threadPool = Executors.newCachedThreadPool();
// 由執行的線程數決定大小。
具體過程:創建線程池對象—>執行---->關閉線程池
try {
for (int i = 1; i <= 10; i++) {
// 使用了線程池之後,使用線程池來創建線程
threadPool.execute(()->{
//執行的線程任務
System.out.println(Thread.currentThread().getName());
});
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 線程池用完,程序結束,關閉線程池
threadPool.shutdown();
}
七大參數
一般開發中使用線程池最好不使用Executors去創建對象。如阿里巴巴開發手冊所說的:OOM(內存溢出)
所以應該使用ThreadPoolExecutor來創建線程池
查看源碼得到以下:
- 當執行線程數大於核心線程鎖時,其它休眠的線程位置將會啓用,最多不超過最大線程數。
- 當超過最大線程鎖的線程任務會在阻塞隊列中進行等待。
- 當此時併發執行的線程任務超過了最大線程數+阻塞隊列長度時,拒絕策略起效。
拒絕策略有四種
new ThreadPoolExecutor.AbortPolicy()
// 同時併發的線程數大於最大線程數+阻塞隊列長度時,不處理超過部分的線程任務,直接拋出異常。new ThreadPoolExecutor.DiscardPolicy()
//同時併發的線程數大於最大線程數+阻塞隊列長度時,直接丟掉超過部分的線程任務,不拋出異常。new ThreadPoolExecutor.CallerRunsPolicy()
// 同時併發的線程數大於最大線程數+阻塞隊列長度時,超過部分的線程任務迴歸main主線程執行。new ThreadPoolExecutor.DiscardOldestPolicy()
//阻塞隊列滿了,嘗試去和最先執行的線程發起競爭,也不會拋出異常!
源碼中的是這樣的:
public ThreadPoolExecutor(int corePoolSize, //核心線程數
int maximumPoolSize, //最大線程數。最多幾個線程併發。
long keepAliveTime, //當線程無任務時,幾秒後結束該線程
TimeUnit unit,//線程結束的時間單位
BlockingQueue<Runnable> workQueue,//阻塞隊列,限制等候線程數
ThreadFactory threadFactory,//線程工廠
RejectedExecutionHandler handler)//拒絕策略
舉個創建的例子:
ExecutorService threadPool = new ThreadPoolExecutor(
2,
Runtime.getRuntime().availableProcessors(),
3,
TimeUnit.SECONDS,
new LinkedBlockingDeque<>(3),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.DiscardOldestPolicy()); //隊列滿了,嘗試去和最早的競爭,也不會拋出異常!
如何選擇線程池的大小
-
IO 密集型 :判斷你程序中十分耗IO的線程,有n個,線程池就設置(2n)個
-
CPU 密集型:一般電腦幾核,線程池就設置幾個線程,可以保持cpu的效率最高!可以利用
Runtime.getRuntime().availableProcessors()
獲取當前主機的核數。