爲什麼《阿里巴巴Java開發手冊》強制不允許使用Executor創建線程池?

看過《阿里Java開發手冊》的你,應該知道

線程池不允許使用Executors去創建,而是通過ThreadPoolExecutor的方式,這樣的處理方式讓寫的同學更加明確線程池的運行規則,規避資源耗盡的風險。

ThreadPoolExecutor機制
核心構造方法講解
下面是ThreadPoolExecutor最核心的構造方法參數:
1)corePoolSize 核心線程池的大小
2)maximumPoolSize 最大線程池大小
3)keepAliveTime 線程池中超過corePoolSize數目的空閒線程最大存活時間;可以allowCoreThreadTimeOut(true)使得核心線程超出有效時間也關閉
4)TimeUnit keepAliveTime的時間單位
5)workQueue阻塞任務隊列
6)threadFactory新建線程工廠
7)RejectedExecutionHandler當提交任務數超過maximumPoolSize+workQueue之和時,任務會交給RejectedExecutionHandler來處理

重點講解
corePoolSize,maximumPoolSize,workQueue三者之間的關係
1)當線程池小於corePoolSize時,新提交的任務會創建一個新線程執行任務,即使線程池中仍有空閒線程。
2)當線程池達到corePoolSize時,新提交的任務將被放在workQueue中,等待線程池中的任務執行完畢
3)當workQueue滿了,並且maximumPoolSize > corePoolSize時,新提交任務會創建新的線程執行任務
4)當提交任務數超過maximumPoolSize,新任務就交給RejectedExecutionHandler來處理
5)當線程池中超過 corePoolSize線程,空閒時間達到keepAliveTime時,關閉空閒線程
6)當設置allowCoreThreadTimeOut(true)時,線程池中corePoolSize線程空閒時間達到keepAliveTime也將關閉

爲什麼上面不允許使用Executors工廠類,要自己定義呢?
1)創建固定大小的線程池。每次提交一個任務就創建一個線程,直到線程達到線程池的最大大小。線程池的大小一旦達到最大值就會保持不變,如果某個線程因爲執行異常而結束,那麼線程池就會補充一個新的線程。
配置的corePoolSize和maximumPoolSize大小相同,同時使用一個無界LinkedBlockingQueue存放阻塞任務,因此多餘的任務將存在再阻塞隊列,不會由RejectedExecutionHandler來處理。

public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}
2)創建一個單線程的線程池。這個線程池只有一個線程在工作,也就是說相當於單線程串行執行所有任務。如果這個唯一的線程因爲異常而結束,那麼會新建一個線程來替換。
此線程池保證所有的任務的執行順序按照任務的提交順序執行。配置corePoolSize = maximumPoolSize = 1,無界阻塞隊列LinkedBlockingQueue;保證任務有一個線程串行執行
public static ExecutorService newSingleThreadExecutor() {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>()));
}
3)創建一個可緩存的線程池。如果線程池的大小超過了處理任務所需要的線程,那麼就會回收部分空閒(60秒)不執行任務的線程,當任務數增加時,此線程池又可以智能的添加新線程來處理任務。
此線程池不會對線程池的大小做限制,線程池的大小完全依賴於操作系統(或者JVM)能夠創建的最大線程大小。配置corePoolSize = 0 maximumPoolSize = Integer.MAX_VALUE keepAliveTime = 60s,以及一個無容量的阻塞隊列SynchronousQueue,因此任務提交之後,將會創建新的線程執行;線程空閒超過60s就會銷燬
public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());
}
4)構造有定時功能的線程池,配置corePoolSize,無界延遲阻塞隊列DelayedWorkQueue;有意思的是:maximumPoolSize = Integer.MAX_VALUE,由於DelayedWorkQueue是無界的,所以這個值是沒有意義的。

public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
    return new DelegatedScheduledExecutorService
        (new ScheduledThreadPoolExecutor(1));
}
我們可以借鑑上面的實現自己的ThreadPoolExecutor

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章