1. 程式人生 > >為什麼阿里Java規約禁止使用Java內建Executors建立執行緒池?

為什麼阿里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:

  主要問題是執行緒數最大數是Integer.MAX_VALUE,可能會建立數量非常多的執行緒,甚至OOM。

看一下這兩種弊端怎麼導致的。

第一種是因為,建立了一個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開發手冊最新版。