工做三年,小胖不知道線程池的阻塞隊列?真的菜!

歡迎來到狗哥多線程系列連載。這篇簡單聊聊線程池的阻塞隊列。java

線程池的內部結構

來源:拉勾教育Java 併發編程.png

如圖所示,線程池的內部結構主要由線程池管理器、工做線程、任務隊列以及任務四部分組成。編程

線程池的阻塞隊列

先上張圖,表格左側是線程池,右側爲它們對應的阻塞隊列,你能夠看到 5 種線程池對應了 3 種阻塞隊列。微信

圖源:拉勾教育Java 併發編程~阻塞隊列.png

下面逐一說下它們的特色:數據結構

  • LinkedBlockingQueue,底層是鏈表結構、採用先進先出原則,默認容量是 Integer.MAX_VALUE,幾乎能夠認爲是無界隊列(幾乎不可能達到這個數)。而因爲 FixedThreadPool 和 SingleThreadExecutor 的線程數是固定的,因此只能用容量無窮大的隊列來存任務
  • SynchronousQueue,容量爲 0,不作存儲,只作轉發。因爲 CachedThreadPool 的最大線程數是 Integer.MAX_VALUE,有任務提交就轉發給線程或者建立新線程來執行,並不須要隊列存儲任務。因此在自定義使用 SynchronousQueue 的線程池應該把最大線程數設置得儘可能大,避免任務數大於最大線程數時,沒辦法把任務放到隊列中也沒有足夠線程來執行任務的狀況。
  • DelayedWorkQueue,內部用的是堆數據結構,初始容量爲 16,跟 hashmap 同樣動態擴容,對任務延時長短進行排序

爲何不自動建立線程池?

阿里巴巴 Java 規約也約定了,手動建立線程池,效果會更好。爲何呢?回答這個問題以前,先來看看五種線程池初始化的方法:多線程

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

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

首先是 FixedThreadPool 和 SingleThreadExecutor,它兩的問題在於都是用默認容量的無界隊列 LinkedBlockingQueue,當任務處理慢時,隊列迅速積壓任務並佔用大量內存,發生 OOM(內存溢出)。因此在使用時咱們能夠根據業務指定隊列長度:併發

ExecutorService threadPool = new ThreadPoolExecutor(2, 5,
    1 L, TimeUnit.SECONDS,
    new LinkedBlockingQueue < > (3),
    Executors.defaultThreadFactory(),
    new ThreadPoolExecutor.AbortPolicy());

而後是 CachedThreadPool,也能夠發現一個問題:它默認的最大線程是 Integer.MAX_VALUE,當任務賊多時,它就會不斷建立線程,而線程執行比較耗時來不及回收。最終也會形成 OOM,因此應該手動指定最大線程數。spa

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

最後是 ScheduledThreadPool 和 ScheduledThreadPoolExecutor,這兩問題就更大了。首先最大線程數是 Integer.MAX_VALUE,而後阻塞隊列是 DelayedWorkQueue,它也是無界隊列,最終仍是會形成 OOM。線程

// ScheduledThreadPool
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
    return new ScheduledThreadPoolExecutor(corePoolSize);
}

// ScheduledThreadPoolExecutor
public ScheduledThreadPoolExecutor(int corePoolSize) {
    super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS, new DelayedWorkQueue());
}

小福利

若是看到這裏,喜歡這篇文章的話,請幫點個好看。微信搜索一個優秀的廢人,關注後回覆電子書送你 100+ 本編程電子書 ,不僅 Java 哦,詳情看下圖。回覆 1024送你一套完整的 java 視頻教程。code

資源

相關文章
相關標籤/搜索