1. 程式人生 > >java 四種執行緒池的簡介

java 四種執行緒池的簡介

前瞻

四種執行緒池內部構造都是來自同一個方法:
這裡寫圖片描述

下面分別介紹一下各個引數的含義:
corePoolSize: 執行緒池中所儲存的核心執行緒數。執行緒池初始化啟動之後,預設是空的,只有當任務來臨之時,才會建立執行緒 處理請求。當然可以使用prestartCoreThread()方法可以使執行緒池初始化之後,立即建立corePoolSize個數的執行緒來等待任務。

maximumPoolSize: 執行緒池中執行緒數能達到的最大值。當然這個引數還與workQueue的使用策略有關,當使用無界佇列(LinkedBlockQueue等)時,本引數無效。corePoolSize和maximumPoolSize的作用是控制執行緒池中實際執行執行緒的數目。例如當新的任務提交到執行緒池時,假設此時執行緒池中執行執行緒的數量為M,當M < corePoolSize時,會新建執行緒來處理任務;如果M>corePoolSize && M < maximumPoolSize時,如果是workQueue是阻塞佇列時,才會建立新的執行緒來完成任務。如果corePoolSize == maximumPoolSize時,則意味著建立了固定大小的執行緒池。如果maximumPoolSize為Integer.MAX_VALUE,則可以理解為該執行緒池適合任意數量的併發任務。

keepAliveTime:當前執行緒池maximumPoolSize > corePoolSize時,終止(maximumPoolSize - corePoolSize)個空閒執行緒的時間。也就是說空閒狀態下,(maximumPoolSize - corePoolSize)個執行緒存活的最長時間。

TimeUnit:keepAliveTime引數的時間單位,可以為毫秒,秒,分。。。

BlockingQueue: 任務佇列,如果當前執行緒池中核心執行緒數達到了corePoolSize時,且當前所有執行緒都屬於活動狀態時,則將新的任務新增到該佇列中。基本上有以下幾個實現:
1) ArrayBlockQueue:基於陣列結構的有界佇列,此佇列按FIFO(first in first out)原則對任務進行排序。如果佇列已滿,新的任務將會被採取拒絕策略對待。
2)LinkedBlockingQueue: 基於連結串列的無界佇列,按FIFO原則排序。因為是無界的,所以不存在滿的情況,此時拒絕策略無效
3) PriorityBlockingQueue:具有優先順序的佇列的有界佇列,可以自定義優先順序,預設為自然排序。

Handler:拒絕策略,當執行緒池和workQueue都滿了的情況下,對新任務採取的處理策略,有四種預設實現:
1) AbortPolicy:拒絕任務,且還丟擲RejectedExecutionException異常,執行緒池預設策略
2) CallerRunPolicy:拒絕新任務進入,如果該執行緒池還沒有被關閉,那麼這個新的任務在執行執行緒中被呼叫
3) DiscardOldestPolicy: 如果執行程式尚未關閉,則位於頭部的任務將會被移除,然後重試執行任務(再次失敗,則重複該過程),這樣將會導致新的任務將會被執行,而先前的任務將會被移除。
4)DiscardPolicy:沒有新增進去的任務將會被拋棄,也不丟擲異常。基本上為靜默模式。

1.FixedThreadPool

由Executors的newFixedThreadPool方法建立。它是一種執行緒數量固定的執行緒池,當執行緒處於空閒狀態時,他們並不會被回收,除非執行緒池被關閉。當所有的執行緒都處於活動狀態時,新的任務都會處於等待狀態,直到有執行緒空閒出來。FixedThreadPool只有核心執行緒,且該核心執行緒都不會被回收,這意味著它可以更快地響應外界的請求。jdk實現如下:

    /*
     * @param nThreads the number of threads in the pool
     * @param threadFactory the factory to use when creating new threads
     * @return the newly created thread pool
     * @throws NullPointerException if threadFactory is null
     * @throws IllegalArgumentException if {@code nThreads <= 0}
     */
    public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>(),
                                      threadFactory);
    }

由此可以看出,FixedThreadPool沒有額外執行緒,只存在核心執行緒,而且核心執行緒沒有超時機制,而且任務佇列沒有長度的限制。

2.CachedThreadPool

由Executors的newCachedThreadPool方法建立,不存在核心執行緒,只存在數量不定的非核心執行緒,而且其數量最大值為Integer.MAX_VALUE。當執行緒池中的執行緒都處於活動時(全滿),執行緒池會建立新的執行緒來處理新的任務,否則就會利用新的執行緒來處理新的任務,執行緒池中的空閒執行緒都有超時機制,預設超時時長為60s,超過60s的空閒執行緒就會被回收。和FixedThreadPool不同的是,CachedThreadPool的任務佇列其實相當於一個空的集合,這將導致任何任務都會被執行,因為在這種場景下SynchronousQueue是不能插入任務的,SynchronousQueue是一個特殊的佇列,在很多情況下可以理解為一個無法儲存元素的佇列。從CachedThreadPool的特性看,這類執行緒比較適合執行大量耗時較小的任務。當整個執行緒池都處於閒置狀態時,執行緒池中的執行緒都會因為超時而被停止回收,幾乎是不佔任何系統資源。實現方式如下:

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

3.ScheduledThreadPool

通過Executors的newScheduledThreadPool方式建立,核心執行緒數量是固定的,而非核心執行緒是沒有限制的,並且當非核心執行緒閒置時它會被立即回收,ScheduledThreadPool這類執行緒池主要用於執行定時任務和具有固定時期的重複任務,實現方法如下:

 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());
    }

4.SingleThreadExecutor

通過Executors的newSingleThreadExecutor方法來建立。這類執行緒池內部只有一個核心執行緒,它確保所有的任務都在同一個執行緒中按順序執行。SingleThreadExecutor的意義在於統一所有外界任務一個執行緒中,這使得這些任務之間不需要處理執行緒同步的問題,實現方式如下:

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

比較如下:
這裡寫圖片描述