线程池ThreadPool,线程池底层ThreadPoolExecutor方法七大参数,拒绝策略,以及实际开发中高并发下用到哪个线程池?
為什么要用線程池
基本的三個線程池的底層就是ThreadPoolExecutor類
ExecutorService threadPool = Executors.newFixedThreadPool(int);//固定線程數的線程池,,執行長期的任務,性能好
ExecutorService threadPool = Executors.newSingleThreadExecutor(); //單線程的線程池,,一個任務一個任務執行
ExecutorService threadPool = Executors.newCachedThreadPool(); //一池N線程,,,執行很多短期異步的任務
Executors是工具類,類似Arrays、Collections
底層ThreadPoolExecutor的重要參數:7大參數(面試一般問前5個)
- int corePoolSize, 線程池中的常駐核心線程數
- int maximumPoolSize, 線程池能夠容納同時執行的最大線程數,此值必須大于等于1(當核心線程數滿了并且阻塞隊列的線程數也滿了,那么就會進行擴容,最大值是maximumPoolSize)
- long keepAliveTime, 多余的空閑線程的存活時間,當前線程池數量超過corePoolSize時,
當空閑時間達到keepAliveTime值時,多余空閑線程會被銷毀直到只剩corePoolSize個線程為止。 - TimeUnit unit, keepAliveTime的單位
- BlockingQueue workQueue, 任務隊列,被提交但尚未被執行的任務。(候客區)
- ThreadFactory threadFactory, 表示生成線程池中的工作線程的線程工廠,用于創建線程一般用默認的即可
- RejectedExecutionHandler handler 拒絕策略,表示當前隊列滿了并且工作線程大于等于線程池的最大線程數(maximumPoolSize)時如何來拒絕請求執行的runnable的策略
當空閑線程空閑的時間超過keepAliveTime,就會被銷毀,但是最少會存在corePoolsize數個線程,如下
線程池的底層工作原理(七大參數如何互動?)
文字講解
2.2 如果正在運行的線程數量小于corePoolSize,那么馬上創建線程運行這個任務。
2.2 如果正在運行的線程數量大于corePoolSize,那么將這個任務加入阻塞隊列
2.3 如果這時候阻塞隊列滿了且正在運行的線程數量小于maximumPoolSize,那么還是要創建非核心線程立刻執行這個任務。
2.4 如果阻塞隊列滿了且正在運行的線程數大于或等于maximumPoolSize,那么線程池會啟動飽和拒絕策略(RejectedExecutionHandler)來執行。
當運行的線程數大于corePoolSize,那么這個線程就被叫停。
所以線程池的所有任務完成后它的線程數最終會收縮到corePoolSize的數量。
線程池的拒絕策略RejectedExecutionHandler(四種)
那么實際的高并發下使用哪個線程池?(面試題)
以上三種高并發下都不會使用:(阿里java開發手冊)
1)第一個圖片可以看到newFixedThreadPool和SingleThreadPool的阻塞隊列用的是LinkedBlockingQueue,Linked底層是鏈表,Integer.MAX_VALUE接近21億,請求可以一直加到阻塞隊列里,那么太多就會OOM。
2)CachedThreadPool和ScheduledThreadPool的第二個參數也就是最大線程數是Integer.MAX_VALUE,可能創建大量線程,導致OOM
接下來繼續測試下每個拒絕策略:(自定義線程池后)
這是自定義的線程池:可以看到核心線程數為2,最大線程數為5,阻塞隊列為3,那么允許請求的最大線程數為5+3=8個
// 自定義線程池ExecutorService threadPool = new ThreadPoolExecutor(2,5,1L,TimeUnit.SECONDS,new LinkedBlockingQueue<Runnable>(3),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());1.AbortPolicy():直接拋出RejectedExecutionException異常阻止系統正常運行
public class MyThreadPoolDemo {public static void main(String []args){// 自定義線程池ExecutorService threadPool = new ThreadPoolExecutor(2,5,1L,TimeUnit.SECONDS,new LinkedBlockingQueue<Runnable>(3),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());try{for (int i = 1; i <= 10 ; i++) {threadPool.execute(()->{System.out.println(Thread.currentThread().getName()+"\t辦理業務");});//TimeUnit.MILLISECONDS.sleep(200);//在Cache線程池里,如果每次暫停0.2秒那么一個線程就可以處理過了,所以每次都是同一個線程,去掉延時就不是一個線程了}}catch (Exception e){e.printStackTrace();}finally {threadPool.shutdown();}}結果:可以看到會拋異常。
2.CallerRunsPolicy():“調用者運行”一種調節機制,該策略既不會拋出任務,也不會拋出異常,而是將某些任務回退到調用調用者,從而降低新的任務流量。()
結果:可以看到多出來的會回退給main線程,(這里可能出現1個main或者沒有main,因為線程執行的太快,阻塞隊列的已經被執行到了,所以可能有偏差)
3.DiscardOldestPolicy() :拋出隊列中等待最久的任務,然后把當前任務加入隊列中嘗試再次提交當前任務
4.DiscardPolicy() :直接丟棄任務,不予任何處理也不拋出異常。如果允許任務丟失,這是最好的一種方案。
那么實際生產中,如何配置自定義線程池的參數呢?
1.CUP密集型:
2.IO密集型
2.1.
2.2
總結
以上是生活随笔為你收集整理的线程池ThreadPool,线程池底层ThreadPoolExecutor方法七大参数,拒绝策略,以及实际开发中高并发下用到哪个线程池?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 矿卡都影响科研了!南大博士高价买到50张
- 下一篇: REVERSE-COMPETITION-