為什麼阿里Java規約禁止使用Java內建Executors建立執行緒池?
IDEA匯入阿里規約外掛,當你這樣寫程式碼時,外掛就會自動監測出來,並給你紅線提醒。
告訴你手動建立執行緒池,效果會更好。
在探祕原因之前我們要先了解一下執行緒池 ThreadPoolExecutor 都有哪些引數及其意義。
ThreadPoolExecutor 構造方法:
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) { //code... }
引數的意義:
1.corePoolSize 指定了執行緒池裡的執行緒數量,核心執行緒池大小
2.maximumPoolSize 指定了執行緒池裡的最大執行緒數量
3.keepAliveTime 當執行緒池執行緒數量大於corePoolSize時候,多出來的空閒執行緒,多長時間會被銷燬。
4.unit 時間單位
5.workQueue 任務佇列,用於存放提交但是尚未被執行的任務。
6.threadFactory 執行緒工廠,用於建立執行緒,一般可以用預設的
7.handler 拒絕策略,當任務過多時候,如何拒絕任務。當提交任務數超過maximumPoolSize + workQueue 的size之和,任務交給RejectedExecutionHandler 處理
阿里規約之所以強制要求手動建立執行緒池,也是和這些引數有關。具體為什麼不允許,規約是這麼說的:
執行緒池不允許使用Executors去建立,而是通過ThreadPoolExecutor的方式,這樣的處理方式讓寫的同學更加明確執行緒池的執行規則,規避資源耗盡的風險。
說明:Executors各個方法的弊端:
1)newFixedThreadPool和newSingleThreadExecutor:
主要問題是堆積的請求處理佇列可能會耗費非常大的記憶體,甚至OOM。
2)newCachedThreadPool和newScheduledThreadPool:
看一下這兩種弊端怎麼導致的。
第一種是因為,建立了一個size為Integer.MAX_VALUE的執行緒阻塞佇列,可能會堆積大量的請求,消耗很大的記憶體,甚至導致OOM。
第二種是因為,建立了的執行緒池允許的最大執行緒數是Integer.MAX_VALUE,可能會建立大量的執行緒,消耗資源,甚至導致OOM。
這兩種都是有點極端的,稍微點進去看一下原始碼就能看出來。
阿里規約提倡手動建立執行緒池,而非Java內建的執行緒池,給出的正例如下:
正例1:
//org.apache.commons.lang3.concurrent.BasicThreadFactory ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(1, new BasicThreadFactory.Builder().namingPattern("example-schedule-pool-%d").daemon(true).build());
正例2:
ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("demo-pool-%d").build(); //Common Thread Pool ExecutorService pool = new ThreadPoolExecutor(5, 200, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(1024), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy()); pool.execute(()-> System.out.println(Thread.currentThread().getName())); pool.shutdown();//gracefully shutdown
正例3:
<bean id="userThreadPool" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor"> <property name="corePoolSize" value="10" /> <property name="maxPoolSize" value="100" /> <property name="queueCapacity" value="2000" /> <property name="threadFactory" value= threadFactory /> <property name="rejectedExecutionHandler"> <ref local="rejectedExecutionHandler" /> </property> </bean> //in code userThreadPool.execute(thread);
---
關注公眾號,程式設計大道,回覆“手冊”獲取阿里Java開發手冊最新版。