java併發編程——線程池

爲了不重複的建立線程,線程池的出現可讓線程進行復用。通俗來說,當有任務提交時,就會向線程池拿一個線程,當任務完成後,並非直接關閉線程,而是將這個線程歸還給線程池供其餘任務使用。html


ThreadPoolExecutor:

ThreadPoolExecutor是線程池的實現類。java

ThreadPoolExecutor的構造器:
數組

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler) {
    if (corePoolSize < 0 ||
        maximumPoolSize <= 0 ||
        maximumPoolSize < corePoolSize ||
        keepAliveTime < 0)
        throw new IllegalArgumentException();
    if (workQueue == null || threadFactory == null || handler == null)
        throw new NullPointerException();
    this.acc = System.getSecurityManager() == null ?
            null :
            AccessController.getContext();
    this.corePoolSize = corePoolSize;
    this.maximumPoolSize = maximumPoolSize;
    this.workQueue = workQueue;
    this.keepAliveTime = unit.toNanos(keepAliveTime);
    this.threadFactory = threadFactory;
    this.handler = handler;
}複製代碼

構造器參數解析:緩存

corePoolSize:線程池的核心池大小,在建立線程池以後,線程池默認沒有任何線程。除非調用了prestartAllCoreThreads()或prestartCoreThread()方法,這兩個方法是預建立線程的方法,即在沒有任務到來以前會建立corePoolSize個線程或者一個線程。默認狀況下,在建立了線程池後,線程池中的線程數爲0,當有任務提交,就會建立一個線程去執行任務,當線程池的線程數目達到corePoolSize後,就會把到達的任務放到緩存隊列中。bash

maximumPoolSize:線程池的最大線程數。若是阻塞隊列滿了,而且已建立的線程數小於最大線程數,則線程池會在建立新的線程執行。ui

keepAliveTime:表示線程沒有任務執行時最多保持多久時間會終止。默認狀況下,當線程池中的線程數大於corePoolSize時,若是一個線程空閒時間達到keepAliveTime,線程則會終止,直到線程池中的線程數不大於corePoolSize。若是調用了allowCoreThreadTimeOut(boolean)方法,在線程池中的線程數不大於corePoolSize時,keepAliveTime參數也會起做用,直到線程池中的線程數爲0。this

unit:參數keepAliveTime的時間單位。spa

workQueue:阻塞隊列,用來存儲等待執行的任務。阻塞隊列通常有如下幾種:線程

ArrayBlockingQueue;//數組結構的有界阻塞隊列,先進先出,建立時必須指定大小
LinkedBlockingQueue;//鏈表結構的無界阻塞隊列,先進先出
SynchronousQueue;//不存儲元素的阻塞隊列,每次插入操做必須等到另外一個線程調用移除操做複製代碼

threadFactory:線程工廠,主要用來建立線程3d

handler:拒絕處理任務策略,有如下四種取值。

ThreadPoolExecutor.AbortFactory;//丟棄任務並拋出RejectedExecutionException異常
ThreadPoolExecutor.DiscardPolicy;//丟棄任務,但不拋出異常
ThreadPoolExecutor.DiscardOldestPolicy;//丟棄隊列最前面的任務,而後從新嘗試執行任務(重複此過程)
ThreadPoolExecutor.CallerRunsPolicy;//由調用線程處理該任務複製代碼

線程池的任務處理策略


首先取得當前線程池中的線程總數,與核心池大小比較,

  • 若是小於核心池大小,將經過addWorker()方法建立線程執行
  • 若是大於,則提交到阻塞隊列
  • 若是阻塞隊列已滿,則把任務直接提交到線程池
  • 若是當前線程數達到最大線程數,則提交失敗,執行拒絕策略,不然分配線程執行。

線程池的關閉

ThreadPoolExecutor提供了兩個方法關閉線程池:

shutdown();//不會當即終止線程池,等全部的任務和阻塞隊列的任務都執行完才終止,但再也不接受新的任務。
shutdownNow();//當即終止線程池,並嘗試打斷正在執行的任務,並清空阻塞隊列,返回還沒有執行的任務複製代碼

線程池的狀態

volatile int runState;
static final int RUNNING = 0;//運行狀態
static final int SHUTDOWN = 1;//關閉狀態
static final int STOP = 2;//中止
static final int TERMINATED = 3;//終止複製代碼

  • 建立線程池後,初始狀態爲RUNNING
  • 若是調用了shutdown(),則線程池處於SHUTDOWN狀態,此時線程池再也不接受新的任務,它會等全部任務執行完畢,最後終止。
  • 若是調用了shutdownNow(),線程池處於STOP狀態,此時線程池不能接受新的任務,而且去嘗試終止正在執行的任務,返回沒有執行的任務列表。
  • 當線程池處於SHUTDOWN或STOP狀態,而且因此工做線程已經銷燬,阻塞隊列已經清空或執行完以後,線程池被設置爲TERMINATED狀態

常見的四種線程池

FixedThreadPool:固定大小的線程池

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

固定大小的線程池,該線程池corePoolSize和maximumPoolSize相等,阻塞隊列爲LinkedBlockingQueue。固定大小的線程池,不存在線程數量的變化。

SingleThreadExecutor:單線程線程池

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

單線程線程池,只有一個線程的線程池,阻塞隊列用LinkedBlockingQueue,如有多餘的任務提交到線程池中,則會被暫存到阻塞隊列,等空閒時再去執行,按照先進先出的順序執行。該線程池可保證任務按照被加入順序執行。

CachedThreadPool:緩存線程池

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

緩存線程池,緩存的線程默認存活60秒。線程池的corePoolSize大小爲0,最大線程數爲Integer.MAX_VALUE,阻塞隊列使用的是SynchronousQueue,是一個直接提交的阻塞隊列,它總會迫使線程池增長新的線程去執行任務。當線程的空間時間超過60s,則工做線程將會終止被回收。當提交新任務時,若是沒有空閒線程,則建立新線程執行任務。

ScheduledThreadPool:定時線程池

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
    return new ScheduledThreadPoolExecutor(corePoolSize);
}複製代碼

定時線程池,可用於週期性地執行任務,一般用於週期性的同步數據。

參考資料:淺入深理解Java線程池及線程池的如何使用

相關文章
相關標籤/搜索