記錄一個多執行緒不建議使用Executors直接建立執行緒池問題
多執行緒兩種方式:
1.通過 Executors 工廠方法建立
2.通過 new ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue workQueue) 自定義建立
相對而言,更建議用第二個建立執行緒池,Executors 建立的執行緒池內部很多地方用到了無界任務佇列,在高併發場景下,無界任務佇列會接收過多的任務物件,嚴重情況下會導致 JVM 崩潰,一些大廠也是禁止使用 Executors 工廠方法去建立執行緒池。newFixedThreadPool 和 newSingleThreadExecutor 的主要問題是堆積的請求處理佇列可能會耗費非常大的記憶體,甚至 OOM;newCachedThreadPool 和 newScheduledThreadPool 的主要問題是執行緒數最大數是 Integer.MAX_VALUE,可能會建立數量非常多的執行緒,甚至 OOM。
new ThreadPoolExecutor描述:
public ThreadPoolExecutor(
int corePoolSize,//執行緒池核心執行緒大小
int maximumPoolSize,//執行緒池最大執行緒數量
long keepAliveTime,//空閒執行緒存活時間
TimeUnit unit,//空閒執行緒存活時間單位,一共有七種靜態屬性(TimeUnit.DAYS天,TimeUnit.HOURS小時,TimeUnit.MINUTES分鐘,TimeUnit.SECONDS秒,TimeUnit.MILLISECONDS毫秒,TimeUnit.MICROSECONDS微妙,TimeUnit.NANOSECONDS納秒)
BlockingQueue<Runnable> workQueue,//工作佇列
ThreadFactory threadFactory,//執行緒工廠,主要用來建立執行緒(預設的工廠方法是:Executors.defaultThreadFactory()對執行緒進行安全檢查並命名)
RejectedExecutionHandler handler//拒絕策略(預設是:ThreadPoolExecutor.AbortPolicy不執行並丟擲異常))
使用示例:
ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 20, 2, TimeUnit.SECONDS, new LinkedBlockingQueue<>(5));5.2.1、工作佇列
jdk 中提供了四種工作佇列:①ArrayBlockingQueue 基於陣列的有界阻塞佇列,按 FIFO 排序。新任務進來後,會放到該佇列的隊尾,有界的陣列可以防止資源耗盡問題。當執行緒池中執行緒數量達到 corePoolSize 後,再有新任務進來,則會將任務放入該佇列的隊尾,等待被排程。如果佇列已經是滿的,則建立一個新執行緒,如果執行緒數量已經達到 maxPoolSize,則會執行拒絕策略。 ②LinkedBlockingQuene 基於連結串列的無界阻塞佇列(其實最大容量為 Interger.MAX_VALUE),按照 FIFO 排序。由於該佇列的近似無界性,當執行緒池中執行緒數量達到 corePoolSize 後,再有新任務進來,會一直存入該佇列,而不會去建立新執行緒直到 maxPoolSize,因此使用該工作佇列時,引數 maxPoolSize 其實是不起作用的。 ③SynchronousQuene 一個不快取任務的阻塞佇列,生產者放入一個任務必須等到消費者取出這個任務。也就是說新任務進來時,不會快取,而是直接被排程執行該任務,如果沒有可用執行緒,則建立新執行緒,如果執行緒數量達到 maxPoolSize,則執行拒絕策略。 ④PriorityBlockingQueue 具有優先順序的無界阻塞佇列,優先順序通過引數 Comparator 實現。
注:原地址連結https://baijiahao.baidu.com/s?id=1682037854549644761&wfr=spider&for=pc