阿里代碼規約爲什麼不讓使用Executors包裝好線程池呢?

在Executors下主要有5個靜態方法:

1. Executors.newWorkStealingPool

  • JDK8引入,創建持有足夠線程的線程池支持給定的並行度,並通過使用多個隊列減少競爭,此構造方法把CPU數量設置爲默認的並行度
    public ForkJoinPool(int parallelism,
                        ForkJoinWorkerThreadFactory factory,
                        UncaughtExceptionHandler handler,
                        boolean asyncMode) {
        this(checkParallelism(parallelism),
             checkFactory(factory),
             handler,
             asyncMode ? FIFO_QUEUE : LIFO_QUEUE,
             "ForkJoinPool-" + nextPoolId() + "-worker-");
        checkPermission();
    }

2. Executors.newCacheThreadPool

  • 這個線程池是一個沒有核心線程數的,且最大線程數是Integer.MAX_VALUE,且使用的隊列是SynchronousQueue,這個隊列有點反人類,他不存儲元素的阻塞隊列,在創建元素的時候每一個put操作必須等待take操作,否則就不能添加元素 。這樣我們就知道了因爲沒有核心線程數,所以剛來的任務我們都會進入到隊列中,但是這個隊列沒有take也不會put,此時那就是說隊列滿了,然後就創建最大線程數。且設置的最大線程數在空閒狀態下的存活時間爲60秒。當有線程閒下來的時候,如果有新的任務來的時候就是用空閒線程,但是有可能出現瞬間來了大量的請求,此時就會無限創建線程直到Integer.MAX_VALUE個線程,很多機器應該在沒有達到之前就會OOM了。創建一個線程就會分配堆,本地方法棧,java虛擬機棧等。所以就很容易就OOM了
    在這裏插入圖片描述
public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }

3. Executors.newScheduledThreadPool

  • 線程數最大到Integer.MAX_VALUE,與上面所說的一樣都有可能會OOM,他是ScheduledExecutorService接口家族的實現類,支持定時及週期性任務執行。與newCacheThreadPool的區別就是不回收工作線程。從下面代碼可以看出到最後也是使用了ThreadPoolExcutor這個類然定義了對應對參數。如設置了最大線程數的存活時間是0秒。

    public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
        return new ScheduledThreadPoolExecutor(corePoolSize);
    }
    
    public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue());
    }
        public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), defaultHandler);
    }

4. Executors.newSingleThreadExecutor

  • 創建一個單線程的的線程池,相當於單線程串行執行任務,保證按任務的提交順序依次執行。這個線程池雖然不會因爲線程創建過多而oom但是會因爲阻塞到隊列而最後產生oom,因爲他使用的是LinkedBlockingQueue 看源碼我們可知他的最大長度也是Integer.MAX_VALUE,所以大量任務的提交也會導致OOM。
    在這裏插入圖片描述

源碼:

    public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }

5. Executors.newFixedThreadPool

  • 輸入的參數即是固定的線程數,即是核心的線程數也是最大的線程數,不存在空閒線程
  • 看下面的源碼我們可知最大線程數和核心線程數是相等的,也就可說只有核心線程數,我們都知道如果核心線程數沒有特定的配置的話核心線程數一旦創建就不會被回收的。但是我們可以看到他使用的也是LinkedBlockingQueue且默認的大小爲Integer.MAX_VALUE,所以也會OOM。
    public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }

其實看了上面的Excutors的五個方法後,在阿里規約裏面時不可以使用除第一個外的四個包內線程的,因爲他們都會引起OOM。

從源碼我們可以看出都是有ThreadPoolExcutor這個類傳入不同的參數而實現的所以說只要我們搞懂其中傳入的7個參數的含義,就可以大概搞懂線程池的冰山一角了

在這裏插入圖片描述

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