1. 程式人生 > >執行緒池基礎類_ThreadPoolExecutor (JDK1.8)

執行緒池基礎類_ThreadPoolExecutor (JDK1.8)

ThreadPoolExecutor

簡介

  ThreadPoolExecutor使用執行緒池執行提交的任務,還維護一些基本統計資訊,例如已完成任務的數量。
  為了適應大多數場景,該方法提供了許多可調引數和鉤子方法。但是推薦使用
Executors工廠方法構造例項:Executors.newCachedThreadPool(無限制執行緒池,具有自動執行緒回收),Executors.newFixedThreadPool(固定大小的執行緒池)和Executors.newSingleThreadExecutor(單個後臺執行緒)。

手動配置調優指南

核心執行緒和最大執行緒數目

  ThreadPoolExecutor根據corePoolSize(請參閱getCorePoolSize)和maximumPoolSize(請參閱getMaximumPoolSize)設定的邊界自動調整池大小(請參閱getPoolSize)。

  • 當一個新任務在方法execute(Runnable)中提交,並且核心執行緒少於corePoolSize執行緒執行時,即使其他工作執行緒處於空閒狀態,也會建立一個新的執行緒來處理該請求。
  • 如果超過corePoolSize但小於maximumPoolSize執行緒執行,則僅當佇列已滿時才會建立一個新執行緒。
  • 通過將corePoolSize和maximumPoolSize設定為相同,可以建立一個固定大小的執行緒池。
  • 通過將maximumPoolSize設定為本質上無限制的值(例如Integer.MAX_VALUE),可以允許池適應任意數量的併發任務。

通常核心和最大池大小隻能在構建時進行設定,但也可以使用setCorePoolSize和setMaximumPoolSize動態更改池大小。

按需構造

  預設情況下,只有在新任務到達時,核心執行緒才會被建立啟動,但可以通過 prestartCoreThread 或prestartAllCoreThreads方法提前啟動這些執行緒。

建立新執行緒

  ThreadPoolExecutor使用ThreadFactory建立執行緒,預設使用Executors.defaultThreadFactory(建立的執行緒位於同一個ThreadGroup裡,並且都使用NORM_PRIORITY優先順序,非守護執行緒)。通過提供一個ThreadFactory,可以改變執行緒名、執行緒組、優先順序、守護性質等。
  如果ThreadFactory建立執行緒時返回null,executor仍會繼續,但可能不會執行任何任務。

存活時間

  如果當前執行緒數超過核心執行緒數,超出的執行緒如果空閒時間超過keepAliveTime指定的時間,則會被終止。可以通過 setKeepAliveTime(long, TimeUnit) 方法動態的修改keepAliveTime。
  設定 Long.MAX_VALUE TimeUnit.NANOSECONDS可以是超時時間生效,通過allowCoreThreadTimeOut(boolean) 方法可以設定超時是否對核心執行緒有效。

排隊

ThreadPoolExecutor使用BlockingQueue儲存任務,該佇列和執行緒大小互動如下:

  • 如果當前執行緒數小於核心執行緒數,則Executor會建立執行緒用於執行任務,而不會把任務交給佇列
  • 如果當前執行緒數大於核心執行緒數,則Executor會把任務交給佇列,而不會建立執行緒
  • 如果任務無法入隊,並且當前執行緒數小於最大執行緒數,則會建立執行緒用於執行任務
  • 如果任務無法入隊,且當前執行緒數大於最大執行緒數,則該任務會被拒絕

有三種入隊的策略

  1. 不儲存任務的佇列。比如SynchronousQueue,每一個put操作必須等待一個take操作,否則不能繼續新增元素。如果沒有一個執行緒可以立即去執行任務,則任務入隊會失敗。
  2. 無界佇列。比如未指定長度的LinkedBlockingQueue(預設長度為Integer.MAX_VALUE),當核心執行緒都在執行時,新加入的任務都會入隊。
  3. 有界佇列。比如ArrayBlockingQueue,可以避免資源耗盡,但是很難調優控制。使用大佇列和小執行緒池可以最大限度地減少CPU使用率,作業系統資源和上下文切換開銷,但可能導致人為的低吞吐量(比如很多執行緒都被IO阻塞)。使用小佇列通常需要較大的池,這樣可以提高CPU利用率,但可能會遇到不可接受的排程開銷,這也降低了吞吐量。

拒絕任務

當Executor被關閉,或者執行緒池和佇列都達到飽和時,提交的任務會被拒絕。在這兩種情況下,execute方法會呼叫RejectedExecutionHandler.rejectedExecution(Runnable, ThreadPoolExecutor) ,有四種預定義的處理策略:
1. ThreadPoolExecutor.AbortPolicy:預設策略,丟擲RejectedExecutionException異常
2. ThreadPoolExecutor.CallerRunsPolicy:呼叫execute()方法的執行緒自己執行提交的任務。這提供了一個簡單的反饋控制機制,將降低新任務提交的速度。
3. ThreadPoolExecutor.DiscardPolicy:任務被簡單丟棄
4. ThreadPoolExecutor.DiscardOldestPolicy:如果Executor沒有關閉,則佇列頭部的任務被刪除,然後重新執行(可能會再次失敗,這會導致重複執行這個邏輯)。

鉤子方法

beforeExecute(Thread, Runnable) 和 afterExecute(Runnable, Throwable)會在每個任務被執行前和執行後被呼叫, terminated()在Executor終止的時候(無任務並且已關閉)時被呼叫。
如果鉤子方法丟擲異常,內部的工作執行緒可能會失敗並突然終止。

佇列維護

方法getQueue()允許訪問工作佇列以進行監視和除錯。 不鼓勵將此方法用於任何其他目的。 當大量排隊任務被取消時,兩種提供的方法,remove(Runnable)和purge可用於協助進行儲存回收。

public class ThreadPoolExecutor extends AbstractExecutorService {

}