java 中四種線程池及 poolSize、corePoolSize、maximumPoolSize


java 中四種線程池及 poolSize、corePoolSize、maximumPoolSize

Executors 提供四種線程池:

  • newCachedThreadPool :緩存線程池,如果線程池長度超過處理需要,可回收空閑線程,若無可回收,則新建線程。
  • newFixedThreadPool : 定長線程池,可控制線程最大並發數,超出的線程會在隊列中等待。
  • newScheduledThreadPool : 計划線程池,支持定時及周期性任務執行。
  • newSingleThreadExecutor :單線程線程池,用唯一的線程來執行任務,保證所有任務按照指定順序 (FIFO, LIFO, 優先級) 執行。

ThreadPoolExecutor 有幾個重要的成員變量:keepAliveTime、allowCoreThreadTimeOut、poolSize、corePoolSize、maximumPoolSize。下面分別介紹一下:

*corePoolSize*線程池的基本大小。下面會解釋什么是基本大小。

maximumPoolSize:線程池中允許的最大線程數。

注意還有一個 largestPoolSize,記錄了曾經出現的最大線程個數。因為 setMaximumPoolSize() 可以改變最大線程數。

poolSize:線程池中當前線程的數量。

那么 poolSize、corePoolSize、maximumPoolSize 三者的關系是如何的呢?

當新提交一個任務時:

(1)如果 poolSize<corePoolSize,新增加一個線程處理新的任務。

(2)如果 poolSize=corePoolSize,新任務會被放入阻塞隊列等待。

(3)如果阻塞隊列的容量達到上限,且這時 poolSize<maximumPoolSize,新增線程來處理任務。

(4)如果阻塞隊列滿了,且 poolSize=maximumPoolSize,那么線程池已經達到極限,會根據飽和策略 RejectedExecutionHandler 拒絕新的任務。

所以通過上面的描述可知 corePoolSize<=maximumPoolSize,poolSize<=maximumPoolSize;而 poolSize 和 corePoolSize 無法比較,poolSize 是有可能比 corePoolSize 大的。

那么 corePoolSize、maximumPoolSize 在上面四種線程池中如何設定的?

通過幾個 newXXX 函數的源碼就可以知道,源碼如下:

(1)

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

定長線程池的 corePoolSize、maximumPoolSize 相同。都是設定值。

(2)

public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());
}

緩存線程池 corePoolSize 為 0,maximumPoolSize 則是 int 最大值。

(3)

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

單線程線程池 corePoolSize 和 maximumPoolSize 都是 1。

(4)

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
    return new ScheduledThreadPoolExecutor(corePoolSize);
}
public ScheduledThreadPoolExecutor(int corePoolSize) {
    super(corePoolSize, Integer.MAX_VALUE,
          DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
          new DelayedWorkQueue());
}

計划線程池用的是 ThreadPoolExecutor 的一個子類,可以看到 corePoolSize 是定義的,而 maximumPoolSize 則是 int 最大值。

注意這里的 corePoolSize、maximumPoolSize 不是最終的,因為可以通過 setCorePoolSize 和 setMaximumPoolSize() 改變。

上面提到阻塞隊列的飽和,那么這個飽和值是多少呢?

通過上面的代碼可以看到

(1)定長線程池和單線程線程都使用 LinkedBlockingQueue,而 LinkedBlockingQueue 默認的大小是 int 的最大值,如下:

public LinkedBlockingQueue() {
    this(Integer.MAX_VALUE);
}

(2)計划線程池使用的是 DelayedWordQueue,它默認大小是 16,但是可以動態增長,最大值則是 int 的最大值,如下:

private static final int INITIAL_CAPACITY = 16;
private RunnableScheduledFuture<?>[] queue =
    new RunnableScheduledFuture<?>[INITIAL_CAPACITY];
private void grow() {
    int oldCapacity = queue.length;
    int newCapacity = oldCapacity + (oldCapacity >> 1); // grow 50%
    if (newCapacity < 0) // overflow
        newCapacity = Integer.MAX_VALUE;
    queue = Arrays.copyOf(queue, newCapacity);
}

(3)緩存線程池使用的則是 SynchronousQueue,這個比較特殊沒有所謂的飽和值,而且前面也看到了緩存線程池的 corePoolSize 默認是 0。所以它新建一個線程與 SynchronousQueue 的機制有關,這里不展開說了,有興趣的可以研究一下這個類。

allowCoreThreadTimeOut:

是否允許核心線程超時退出。

如果該值為 false,且 poolSize<=corePoolSize,線程池都會保證這些核心線程處於存活狀態,不會超時退出。

如果為 true,則不論 poolSize 的大小,都允許超時退出。

如果 poolSize>corePoolSize,則該參數不論 true 還是 false,都允許超時退出。

相關判斷如下:

(poolSize> corePoolSize || allowCoreThreadTimeOut)

keepAliveTime:

如果一個線程處在空閑狀態的時間超過了該屬性值,就會因為超時而退出。是否允許超時退出則取決於上面的邏輯。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM