1. 程式人生 > >Java 四種常見執行緒池解析

Java 四種常見執行緒池解析

四種常見執行緒池

  執行緒池用於管理執行緒的建立與銷燬,避免無用執行緒造成資源浪費,當需要建立多個執行緒時,我們往往需要一個管理者來管理這些執行緒,這也就引入了執行緒池的概念.Android中有四種較為常見的執行緒池也是我們使用最廣泛的執行緒池,FixedThreadPool(固定執行緒數的執行緒池),ChachedThreadPool(快取型執行緒池),SingleThreadExecutor(單執行緒執行緒池),ScheduledThreadPool(週期性排程執行緒池).這幾種執行緒池本質都是通過ThreadPoolExecutor來建立的.當然在使用中我們只需要通過Executors就能快速建立這幾類執行緒池,但是我們需要理解其建立的具體流程.

執行緒池工作流程

ThreadPoolExecutor

  這四種常見執行緒池建立的本質都是通過ThreadPoolExecutor來建立的,只是傳入的引數不同就生成了不同的執行緒池,所以我們需要學習ThreadPoolExecutor的構造方法,這樣我們就可以創建出符合我們需求的執行緒池了.

ThreadPoolExecutor的重要屬性

  • corePoolSize:核心執行緒數,預設情況執行緒池為空,只有在提交任務後,才會建立新的執行緒去執行任務,當正在執行的執行緒數少於核心執行緒數時,則建立新執行緒來執行任務;如果等於或者多於核心執行緒數,則不再建立.如果使用prestartAllcoreThread方法,則會提前建立執行緒填滿執行緒池,等待任務.
  • maximumPoolSize:執行緒池允許建立的最大執行緒數(包括核心執行緒與非核心執行緒),如果任務佇列已經滿了,但是小於maximumPoolSize,仍然可以建立非核心執行緒來執行任務.
  • keepAliveTime:非核心執行緒的閒置時間,非核心執行緒一旦存活時間超過keepAliveTime則會被回收,如果有很多重複任務則可以提高keepAliveTime來保證執行緒的重複利用率,如果設定了allowCoreThreadTimeOut屬性為true.
  • TimeUtil:keepAliveTime的單位,包含天,時,分,秒,毫秒等.
  • WorkQueue:任務佇列,這是一個阻塞佇列.
  • ThreadFactory:執行緒工廠,通過執行緒工廠可以為執行緒取名,一般無需使用.
  • RejectedExecutionHandler:飽和策略,當任務和執行緒池都滿了時採用的處理方法,預設為AbordPolicy策略表示無法處理新任務.

飽和策略

  飽和策略就是當任務佇列和執行緒池都已經滿了的時候,有新任務進來時採用何種策略來處理新任務.

  • AbordPolicy:表示無法處理新任務
  • CallerRunsPolicy:通過呼叫者所線上程處理新任務.
  • DiscardPolicy:無法執行新任務,並刪除該任務
  • DiscardOldestPolicy:丟棄佇列最近的任務並執行該任務.

FixedThreadPool

  FixedThreadPool的核心執行緒數和最大執行緒數都指定為同一值也就意味著,該執行緒池中只包含了核心執行緒,並且核心執行緒數量已經規定好了,其傳入的keepAliveTime為0L表示,一旦任務執行完畢,執行緒空閒就會立即被回收.其傳入的任務佇列為LinkedBlockingQueue(無界阻塞佇列即任務數量沒有限制),如果執行緒多於核心執行緒數時,任務會被放入任務佇列中,等待能建立新執行緒時再執行.

使用中我們通過Excutors來建立FixedThreadPool

Executors.newFixedThreadPool();

FixedThreadPool建立原始碼

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

ChachedThreadPool

  ChachedThreadPool執行緒池中核心執行緒數為0,其最大執行緒數為Integer.MAX_VALUE(即無界),這也意味著所有執行緒都為非核心執行緒,任務佇列為SynchronousQueue(阻塞佇列),當任務執行完畢後執行緒可以存活60秒來等待任務匹配,如果沒有任務則被銷燬,如果匹配上了任務,則提高了執行緒的重複利用率.該執行緒池適用於大量需要立即執行的任務且任務週期較短的任務.

使用中我們通過Excutors來建立ChachedThreadPool

Executors.newCachedThreadPool();

ChachedThreadPool建立原始碼

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

SingleThreadExecutor

  單執行緒池,該執行緒池中只存在一個核心執行緒,任務佇列為LinkedBlockingQueue,即該執行緒池會把任務放入該無界阻塞佇列中一個一個執行.

使用中我們通過Excutors來建立SingleThreadExecutor

Executors.newSingleThreadExecutor();

SingleThreadExecutor建立原始碼

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

ScheduledThreadPool

  定時排程執行緒,該執行緒可以實現延時和週期性迴圈任務.具有固定的核心執行緒數以及無界的非核心執行緒數,任務佇列為DelayedWorkQueue(延時佇列),DelayedWorkQueue佇列會將任務按照順序排列,將先執行的任務放在佇列前端.

使用中我們通過Excutors來建立ScheduledThreadPool

Executors.newScheduledThreadPool();

ScheduledThreadPool建立原始碼

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

ScheduledThreadPoolExecutor的構造方法   這裡呼叫了其super方法,其父類就是ThreadPoolExecutor,所以本質上ScheduledThreadPool也是通過ThreadPoolExecutor建立的.但是有一點不同ScheduledThreadPool的管理佇列是一個延時佇列,所以它可以定時排程執行緒.

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