1. 程式人生 > >Executors建立ExecutorService(執行緒池)的常用方法

Executors建立ExecutorService(執行緒池)的常用方法

一、執行緒池的建立

JDK中提供了4個可過載的構造方法來建立一個執行緒池,當然萬變不離其中,引數少的構造方法將使用預設的引數呼叫引數多的構造方法。如下為其中兩個構造方法是,第一個構造方法將呼叫第二個構造方法:

構造方法一:

public ThreadPoolExecutor(int corePoolSize,
                            int maximumPoolSize,
                            long keepAliveTime,
                            TimeUnit unit,
                            BlockingQueue<</span>Runnable> workQueue) {
      this

(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
           Executors.defaultThreadFactory(), defaultHandler);
  }

構造方法二:

public ThreadPoolExecutor(int corePoolSize,
                            int maximumPoolSize,
                            long keepAliveTime,
                            TimeUnit unit,
                            BlockingQueue<</span>Runnable> workQueue) {
      this

(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
           Executors.defaultThreadFactory(), defaultHandler);
  }

建立一個執行緒池需要輸入的引數說明:

  • corePoolSize(執行緒池的基本大小):當提交一個任務到執行緒池時,執行緒池會建立一個執行緒來執行任務,即使其他空閒的基本執行緒能夠執行新任務也會建立執行緒,等到需要執行的任務數大於執行緒池基本大小時就不再建立(這時新加入的任務將會放在任務佇列中,如果佇列滿了,執行緒個數還沒有超過最大數,則才會再建立執行緒)。如果呼叫了執行緒池的prestartAllCoreThreads方法,執行緒池會提前建立並啟動所有基本執行緒。
  • workQueue(任務佇列):用於儲存等待執行的任務的阻塞佇列。 可以選擇以下幾個阻塞佇列。
    • ArrayBlockingQueue:是一個基於陣列結構的有界阻塞佇列,此佇列按 FIFO(先進先出)原則對元素進行排序。
    • LinkedBlockingQueue:一個基於連結串列結構的阻塞佇列,此佇列按FIFO (先進先出) 排序元素,吞吐量通常要高於ArrayBlockingQueue。靜態工廠方法Executors.newFixedThreadPool()使用了這個佇列。
    • SynchronousQueue:一個不儲存元素的阻塞佇列。每個插入操作必須等到另一個執行緒呼叫移除操作,否則插入操作一直處於阻塞狀態,吞吐量通常要高於LinkedBlockingQueue,靜態工廠方法Executors.newCachedThreadPool使用了這個佇列。
    • PriorityBlockingQueue:一個具有優先順序的無限阻塞佇列。
  • maximumPoolSize(執行緒池最大大小):執行緒池允許建立的最大執行緒數。如果佇列滿了,並且已建立的執行緒數小於最大執行緒數,則執行緒池會再建立新的執行緒執行任務。值得注意的是如果使用了無界的任務佇列這個引數就沒什麼效果。
  • ThreadFactory:用於設定建立執行緒的工廠,可以通過執行緒工廠給每個創建出來的執行緒設定更有意義的名字。
  • RejectedExecutionHandler(飽和策略):當佇列和執行緒池都滿了,說明執行緒池處於飽和狀態,那麼必須採取一種策略處理提交的新任務。這個策略預設情況下是AbortPolicy,表示無法處理新任務時丟擲異常。以下是JDK1.5提供的四種策略。
    • AbortPolicy:直接丟擲異常。
    • CallerRunsPolicy:只用呼叫者所線上程來執行任務。
    • DiscardOldestPolicy:丟棄佇列裡最先進去的一個任務,並執行當前任務。
    • DiscardPolicy:不處理,丟棄掉。
    • 當然也可以根據應用場景需要來實現RejectedExecutionHandler介面自定義策略。如記錄日誌或持久化不能處理的任務。
  • keepAliveTime(執行緒活動保持時間):執行緒池的工作執行緒空閒後,保持存活的時間。所以如果任務很多,並且每個任務執行的時間比較短,可以調大這個時間,提高執行緒的利用率。
  • TimeUnit(執行緒活動保持時間的單位):可選的單位有天(DAYS),小時(HOURS),分鐘(MINUTES),毫秒(MILLISECONDS),微秒(MICROSECONDS, 千分之一毫秒)和毫微秒(NANOSECONDS, 千分之一微秒)。

二、Executors提供了一些方便建立ThreadPoolExecutor的常用方法,主要有以下幾個:

1、 Executors.newFixedThreadPool(int nThreads);

說明:建立固定大小(nThreads, 大小不能超過int的最大值)的執行緒池

// 執行緒數量  int nThreads = 20;

// 建立executor 服務  : ExecutorService executor = Executors.newFixedThreadPool(nThreads) ;

過載後的版本,需要傳入實現了ThreadFactory介面的物件。

              ExecutorService executor = Executors. newFixedThreadPool(nThreads, threadFactory);

說明:建立固定大小(nThreads, 大小不能超過int的最大值) 的執行緒池,緩衝任務的佇列為LinkedBlockingQueue,大小為整型的最大數,當使用此執行緒池時,在同執行的任務數量超過傳入的執行緒池大小值後,將會放入LinkedBlockingQueue,在LinkedBlockingQueue中的任務需要等待執行緒空閒後再執行,如果放入LinkedBlockingQueue中的任務超過整型的最大數 時,丟擲RejectedExecutionException。

2、Executors.newSingleThreadExecutor():建立大小為1的固定執行緒池。

ExecutorService executor = Executors.newSingleThreadExecutor();

過載後的版本,需要多傳入實現了ThreadFactory介面的物件。

ExecutorService executor = Executors. newSingleThreadScheduledExecutor(ThreadFactory threadFactory) 

說明:建立大小為1的固定執行緒池,執行任務的執行緒只有一個,其它的(任務)task都放在LinkedBlockingQueue中排隊等待執行。

3、Executors.newCachedThreadPool();建立corePoolSize為0,最大執行緒數為整型的最大數,執行緒  keepAliveTime為1分鐘,快取任務的佇列為SynchronousQueue的執行緒池。

ExecutorService executor = Executors.newCachedThreadPool();

當然也可以以下面的方式建立,過載後的版本,需要多傳入實現了ThreadFactory介面的物件。

ExecutorService executor = Executors.newCachedThreadPool(ThreadFactory threadFactory) ;

說明:使用時,放入執行緒池的task任務會複用執行緒或啟動新執行緒來執行,注意事項:啟動的執行緒數如果超過整型最大值後會丟擲RejectedExecutionException異常,啟動後的執行緒存活時間為一分鐘

4、Executors.newScheduledThreadPool(int corePoolSize):建立corePoolSize大小的執行緒池。

// 執行緒數量 int corePoolSize= 20;

// 建立executor 服務 : ExecutorService executor = Executors.newScheduledThreadPool(corePoolSize) ;

過載後的版本,需要多傳入實現了ThreadFactory介面的物件。

ExecutorService executor = Executors.newScheduledThreadPool(corePoolSize, threadFactory) ;

說明:執行緒keepAliveTime為0,快取任務的佇列為DelayedWorkQueue,注意不要超過整型的最大值。

備註:

FixedThreadPool 模式會使用一個優先固定數目的執行緒來處理若干數目的任務。規定數目的執行緒處理所有任務,一旦有執行緒處理完了任務就會被用來處理新的任務(如果有的話)。這種模式與上面的CachedThreadPool是不同的。

CachedThreadPool 模式下處理一定數量的任務的執行緒數目是不確定的。而FixedThreadPool模式下最多的執行緒數目是一定的。

SingleThreadExecutor 模式只會建立一個執行緒。它和FixedThreadPool比較類似,不過執行緒數是一個。 如果多個任務被提交給SingleThreadExecutor的話 ,那麼這些任務會被儲存在一個佇列中,並且會按照任務提交的順序,一個先執行完成再執行另外一個執行緒。 SingleThreadExecutor模式可以保證只有一個任務會被執行。 這種特點可以被用來處理共享資源的問題而不需要考慮同步的問題。