Java中官方推薦的線程池有四種:線程池介紹參考:https://www.cnblogs.com/CarpenterLee/p/9558026.html;在jdk1.8加入了 ForkJoinPool的擴展,newWorkStrealingPool,能夠合理的使用CPU對任務進行並行操作,適合用於耗時的操作
但是這幾種線程池會造成OOM的問題;
1、阻塞隊列是無界的,導致不停的往隊列中加任務,最后導致溢出;
2、啟用的線程數量 過多,例如newCachedThreadPool ,這種線程池的maxmumPoolSize是max_Integer 所以如果當前線程數大於core並且隊列已滿的情況下,就會創建新線程,如果aliveTime時間較長沒有及時GC掉,最終導致溢出;
所以一般推薦使用 new ThreadPoolExecutor(int corePoolSize,int maxNumPoolSize,long keepAliveTime,TimeUnit,BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler policy)來進行自定義線程池;在這里先重點梳理一下線程池中的阻塞隊列和拒絕策略:
阻塞隊列有:
基於數組結構的: ArrayBlockingQueue :創建時要指定一個容量;
基於鏈表結構的: LinkedBlockingQueue、LinkedBlockingDeque 創建時可以指定容量,不指定則默認為一個無界隊列;newFixedThreadPool、newSingleThreadPool、用的是這個無界的Queue
同步的: SynchronousQueue:容量為0,這種同步隊列只有在有線程寫入元素時,另一個線程才能通過poll獲取到元素,否則返回null;簡單來說這種隊列將任務直接提交,而不維持隊列,在自定義線程池中默認的隊列;newCachedThreadPool用的是這個
混合的:DelayedWorkQueue:基於DelayQueue和PriorityQueue,是延遲的並且具有自然排序的阻塞隊列;newScheduledThreadPool用這個。
PriorityBlockingQueue: 一個支持優先級排序的無界阻塞隊列,對元素沒有要求,可以實現Comparable接口也可以提供Comparator來對隊列中的元素進行比較,跟時間沒有任何關系,僅僅是按照優先級取任務。
拒絕策略:
作用場景:在隊列已滿,並且線程數量達到了maxmumPoolSize的時候;
拒絕策略的接口是: RejectedExecutionHandler;ThreadPoolExecutor中提供了四個靜態方法返回實現了該接口的對象:
AbortPolicy:拋出RejectedExecutionException異常
CallerRunsPolicy:直接由提交任務者來執行這個任務(一般是main線程);因此使用這種策略會導致主線程堵塞;容易導致故障
DiscardOldesPolicy:彈出隊列中最年長的任務,嘗試將要執行的任務加到隊列中;
DiscardPolicy:忽略這個任務,不拋出異常
附一張很好的線程池工作流程圖: