1. 程式人生 > >Java基礎學習——多執行緒之執行緒池

Java基礎學習——多執行緒之執行緒池

1.執行緒池介紹

    執行緒池是一種執行緒使用模式。執行緒由於具有空閒(eg:等待返回值)和繁忙這種不同狀態,當數量過多時其建立、銷燬、排程等都會帶來開銷。執行緒池維護了多個執行緒,當分配可併發執行的任務時,它負責排程執行緒執行工作,執行完畢後執行緒不關閉而是返回執行緒池,可以執行後續其他任務。舉例來說,外賣餐廳對每個訂單分配一個臨時工,完成訂單立刻辭退,成本和管理開銷巨大,而且如果取餐點的空間有限,大量的人擠滿在那反而會影響工作效率,因此選擇簽下固定數量的外賣小哥讓他們不斷往返於目的地和店家之間配送。

    通俗來講,執行緒池就是為了減少開銷而複用執行緒,實現了任務內容和執行緒分離的一種機制。如果機器有100核而且其他資源充足,直接啟動100個無衝突的併發執行緒應該是比使用執行緒池要快,但是受限於目前的硬體能力,執行緒池就很有必要了。Java的Executor框架用於執行非同步任務,方法 executor(Runnable runnable)

 可以接收Runnable物件。Executor有一個子類介面ExecutorService,提供了生命週期管理的方法,以及可跟蹤一個或多個非同步任務執行狀況返回Future的方法。

2.工廠模式建立執行緒池

     Excutors運用工廠模式提供執行緒池實現方式,返回ExecutorService

  1. newSingleThreadExecutor,單執行緒的執行緒池,實際上是序列執行任務,如果該執行緒出現異常則會有新執行緒替代它工作,其優勢是任務會按照提交順序執行。

  2. newFixedThreadPool,固定大小執行緒池,每次新提交任務時如果執行緒數沒達到最大就建立新執行緒執行任務,否則任務進入等待狀態。

  3. newCachedThreadPool,可快取的執行緒池,大小依賴於作業系統(JVM)最大值。執行緒池大於任務數時回收部分空閒(60s)執行緒,任務數增加時新增新執行緒。

    問題在於,前兩者請求處理佇列的堆積會消耗記憶體,第三個建立過多執行緒也會這樣。同時,拒絕策略在Executors中無效。

3.自定義建立

    ThreadPoolExecutor是執行緒池的實現方法簽名:

public ThreadPoolExecutor(int corePoolSize,
                          int
maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) //後兩個引數為可選引數

 

  1. corePoolSize,核心執行緒數,同時處於執行狀態的執行緒最大值(或者說,接單配送中的小哥人數上限)。當執行緒數少於該值時,新的任務會建立新的執行緒執行。allowCoreThreadTimeOut屬性不設定為true(預設false)時,閒置的核心執行緒也不會銷燬。
  2. maximumPoolSize,執行緒總數,等於核心執行緒+非核心執行緒數,不小於核心執行緒數。
  3. keepAliveTime,執行緒進入不活躍狀態後到銷燬前的時間,通過Unit引數設定單位。通常只適用於非核心執行緒,allowCoreThreadTimeOut為true時核心執行緒也適用。
  4. workQueue,任務佇列,當核心執行緒滿時新任務進入該佇列等待,當佇列滿時建立非核心執行緒執行任務。
    • SynchronousQueue:等於沒有佇列,任何任務都直接給執行緒處理,為防止執行緒數量達到最大值,通常設定maximumPoolSize為Integer.MAX_VALUE
    • LinkedBlockingQueue:無限長阻塞佇列,匯流排程數永遠等於核心執行緒數,未執行的任務都在佇列裡排隊
    • ArrayBlockingQueue:定長佇列,佇列滿時新建非核心執行緒,達到maximumPoolSize後出錯
    • DelayQueue,當任務實現Delayed介面時,任務入隊等待到指定延時後開始執行
  5. threadFactory,執行緒工廠
  6. handler,任務被拒絕時的策略
    • AbortPolicy,預設策略,將丟擲RejectExecutorException
    • CallerRunsPolicy,執行緒池未關閉時呼叫執行緒(任務提交者)直接執行該任務
    • DiscardPolicy,直接丟棄不丟擲異常
    • DiscardOldestPolicy,丟棄佇列最前的任務後重試當前任務

4.生命週期

    ExecutorService的生命週期包括了執行、關閉和終止三種狀態,在初始化建立時處於執行狀態。使用submit方法執行Runnable或者Callable物件。shutdown方法等待提交的任務執行完成並不再接受新任務,在完成全部提交的任務後關閉;shutdownNow方法將強制終止所有執行中的任務並不再允許提交新任務。