ThreadPoolExecutor 源碼解析

在阿里巴巴的《Java開發手冊》中是這樣規定線程池的:

線程池不允許使用Executors去創建,而是通過ThreadPoolExecutor的方式,這樣的處理方式讓寫的讀者更加明確線程池的:

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

說明:Executors返回的線程池對象的弊端如下:

1)FixedThreadPool和SingleThreadPool:允許的請求隊列長度爲Integer.MAX_VALUE,可能會堆積大量請求,從而導致OOM

2) CachedThreadPool 和 ScheduledThreadPool: 允許的創建線程數量爲Integer.MAX_VALUE,可能會創建大量線程,從而到時OOM

其實當我們去看Executors的源碼會發現,Executors.newFixedThreadPool()、Executors.newSingleThreadExecutor()和Executors.newCachedThreadPool等方法的底層都是通過ThreadPoolExecutor 實現的.



public class Executors {

    public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }

    public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }
   
    public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }
    
    // 那構造器最全的參數舉例
    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
        if (corePoolSize < 0 ||
            // maximumPoolSize 必須大於0,且必須大於  corePoolSize 
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.acc = System.getSecurityManager() == null ?
                null :
                AccessController.getContext();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

}

   1.  int corePoolSize : 標識線程池的常駐核心線程數.

                                    如果等於0,則標識在沒有任何任務的時候,銷燬線程池.

                                    如果大於0 ,即使沒有任務時,也會保證線程池的線程數量等於次值. 但需要注意的是,如果此值設置的比較小,

                                    則會頻繁創建和銷燬線程

                                    如果設置的比較大,則會浪費系統資源,所以程序要需要根據自己的實際業務來調整此值.

 2. int maximumPoolSize :表示線程池在任務最多時,最大可以創建的線程數.

                                       官方規定此值必須大於0,同時也必須大於 corePoolSize, 此值只有在任務比較多的時候,且不能存放在任                                           務隊列時,纔會用到.

3. long keepAliveTime: 表示線程的存活時間,當線程池空閒時並且超過了此時間,多餘的線程就會銷燬,直到線程池中的線程數量銷燬等於corePoolSize爲止.

                                如果 maximumPoolSize 等於corePoolSize,那麼線程池在空閒的時候,也不會銷燬任何線程.

4.TimeUnit unit : 表示存活時間的單位,它是配合keepAliveTime 參數共同使用的

5.BlockingQueue<Runnable> workQueue :表示線程池執行的任務隊列,當線程池的所有線程都在處理任務時,如果來了新任務會緩存到此任務隊列中排隊等待執行.

6.ThreadFactory threadFactory: 表示線程的創建工廠,這個參數一般用的比較少,我們通常在創建線程時不指定此參數,它會使用默認的線程創建工廠的方法來創建線程



 public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), defaultHandler);
  }

  public static ThreadFactory defaultThreadFactory() {
        return new DefaultThreadFactory();
  }

  // 默認的線程創建工廠,需要創建ThreadFactory 
  static class DefaultThreadFactory implements ThreadFactory {
        private static final AtomicInteger poolNumber = new AtomicInteger(1);
        private final ThreadGroup group;
        private final AtomicInteger threadNumber = new AtomicInteger(1);
        private final String namePrefix;

        DefaultThreadFactory() {
            SecurityManager s = System.getSecurityManager();
            group = (s != null) ? s.getThreadGroup() :
                                  Thread.currentThread().getThreadGroup();
            namePrefix = "pool-" +
                          poolNumber.getAndIncrement() +
                         "-thread-";
        }

        public Thread newThread(Runnable r) {
            Thread t = new Thread(group, r,
                                  namePrefix + threadNumber.getAndIncrement(),
                                  0);
            if (t.isDaemon())
                // 創建一個非守護線程
                t.setDaemon(false);
            if (t.getPriority() != Thread.NORM_PRIORITY)
                // 優先級設置爲默認值
                t.setPriority(Thread.NORM_PRIORITY);
            return t;
        }
    }

7.RejectedExecutionHandler handler: 表示指定線程池的拒絕策略. 當線程池的任務已經在緩存隊列 workQueue  中存儲滿了之後,並且不能創建新的線程來執行此任務時,就會用到此拒絕策略,它屬於一種限流保護機制. 

ThreadPoolExecutor 自帶了4中拒絕策略:

new ThreadPoolExecutor.AbortPolicy():終止策略,線程池會拋出異常並終止執行,它是默認的拒絕策略.
new ThreadPoolExecutor.CallerRunsPolicy():報任務提交給當前線程來執行
new ThreadPoolExecutor.DiscardPolicy(): 忽略此任務(最新的任務)
new ThreadPoolExecutor.DiscardOldestPolicy():忽略最早的任務(最先加入隊列的任務)

通過看源碼以上4種拒絕策略均實現了RejectedExecutionHandler ,因此要自定義拒絕策略:

public interface RejectedExecutionHandler {
     void rejectedExecution(Runnable r, ThreadPoolExecutor executor);
}

也應該實現該接口就可以了

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