Executors提供了三個經典的線程池創建方式
ExecutorService threadPool = Executors.newFixedThreadPool(int)
ExecutorService threadPool = Executors.newSingleThreadPool()
ExecutorService threadPool = Executors.newCachedThreadPool(int)
那我們在工作中到底用哪一個呢?
答案是我們在生產上只能用自定義的
根據圖中我們可以發現他們得底層實現都是用了ThreadPoolExecutor,然而第五個參數使用到的阻塞隊列默認值是Integer.MAX_VALUE,也就是
2147483647,這樣就相當於是一個無界的隊列。所有的請求都往里塞,最終造成OOM。
根據阿里編碼規范也可以看出
參數說明
線程池底層實現的7大參數
1.corePoolSize:線程池中的常駐核心線程數
2.maximumPoolSize:線程池能夠容納同時執行的最大線程數,此值必須大於等於1
3.keepAliveTime:多余的空閑線程的存活時間
4.unit:keepAliveTime的單位
5.workQueue:任務隊列,被提交但尚未被執行的任務。
6.threadFactory:表示生成線程池中工作線程的線程工廠,用於創建線程一般用默認
7.handler:拒絕策略,表示當隊列滿了並且工作線程大於等於線程池的最大線程數
工作原理
線程池的底層工作原理
core基本線程數,當線程數大於corePoolSize時,多余線程將轉入阻塞隊列,阻塞隊列也滿了之后
將擴容到maximumPoolSize數。maximumPoolSize也滿了之后將采取拒絕策略。
當線程數小了之后,根據設定的空閑線程存活時間將線程總容量回縮到corePoolSize
手動實現
* 線程池demo
* @author t
* 實際工作中對多線程的使用都是線程池,不會顯示的創建線程
* 而使用傳統方式的方法創建線程池容易造成oom
*/
public class ThreadPoolDemo {
2,
5,
1,
TimeUnit.SECONDS,
new LinkedBlockingDeque<>(3),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());
try {
for (int i = 1; i <= 10; i++) {
final int num = i;
threadPool.execute(() -> {
//打印當前線程名稱
//暫停一會線程
System.out.println("序號 "+num+" "+Thread.currentThread().getName()+" \t 辦理業務");
});
}
}catch (Exception e){
e.printStackTrace();
}finally {
threadPool.shutdown();
}
}
}
運行結果
注意:根據機器配置不同運行效果也不同,本來應該是超過最大線程數(maximumPoolSize+隊列大小)就會觸發拒絕策略,但是由於機器處理速度
能夠處理的過來,所以沒有報錯。
線程暫停1秒,9個線程的運行結果
作者:ushowtime