CTF misc 第六天
一 入參
corePoolSize: 執行緒池核心執行緒數,當初始化執行緒池時,會建立核心執行緒進入等待狀態,即使它是空閒的,核心執行緒也不會被摧毀,從而降低了任務一來時要建立新執行緒的時間和效能開銷。當allowCoreThreadTimeOut手動設定為true,才會銷燬
maximumPoolSize: 最大執行緒數,意味著核心執行緒數都被用完了,那隻能重新建立新的執行緒來執行任務,但是前提是不能超過最大執行緒數量,否則該任務只能進入阻塞佇列進行排隊等候,直到有執行緒空閒了,才能繼續執行任務
keepAliveTime: 執行緒存活時間,除了核心執行緒外,那些被新創建出來的執行緒可以存活多久。意味著,這些新的執行緒一但完成任務,而後面都是空閒狀態時,就會在一定時間後被摧毀
threadFactory:就是建立執行緒的執行緒工廠
unit: 執行緒存活時間單位
workQueue: 表示任務的阻塞佇列,由於任務可能會有很多,而執行緒就那麼幾個,所以那麼還未被執行的任務就進入佇列中排隊,佇列我們知道是 FIFO 的,等到執行緒空閒了,就以這種方式取出任務。這個一般不需要我們去實現。handler的拒絕策略有四種:
第一種AbortPolicy:不執行新任務,直接丟擲異常,提示執行緒池已滿
第二種DisCardPolicy:不執行新任務,也不丟擲異常
第三種DisCardOldSetPolicy:將訊息佇列中的第一個任務替換為當前新進來的任務執行
第四種CallerRunsPolicy:直接呼叫execute來執行當前任務
1. LinkedBlockingQueue
對於 FixedThreadPool 和 SingleThreadExector 而言,它們使用的阻塞佇列是容量為 Integer.MAX_VALUE 的 LinkedBlockingQueue,可以認為是無界佇列。由於 FixedThreadPool 執行緒池的執行緒數是固定的,所以沒有辦法增加特別多的執行緒來處理任務,這時就需要 LinkedBlockingQueue 這樣一個沒有容量限制的阻塞佇列來存放任務。這裡需要注意,由於執行緒池的任務佇列永遠不會放滿,所以執行緒池只會建立核心執行緒數量的執行緒,所以此時的最大執行緒數對執行緒池來說沒有意義,因為並不會觸發生成多於核心執行緒數的執行緒。
2. SynchronousQueue
第二種阻塞佇列是 SynchronousQueue,對應的執行緒池是 CachedThreadPool。執行緒池 CachedThreadPool 的最大執行緒數是 Integer 的最大值,可以理解為執行緒數是可以無限擴充套件的。CachedThreadPool 和上一種執行緒池 FixedThreadPool 的情況恰恰相反,FixedThreadPool 的情況是阻塞佇列的容量是無限的,而這裡 CachedThreadPool 是執行緒數可以無限擴充套件,所以 CachedThreadPool 執行緒池並不需要一個任務佇列來儲存任務,因為一旦有任務被提交就直接轉發給執行緒或者建立新執行緒來執行,而不需要另外儲存它們。
我們自己建立使用 SynchronousQueue 的執行緒池時,如果不希望任務被拒絕,那麼就需要注意設定最大執行緒數要儘可能大一些,以免發生任務數大於最大執行緒數時,沒辦法把任務放到佇列中也沒有足夠執行緒來執行任務的情況。
3. DelayedWorkQueue
第三種阻塞佇列是DelayedWorkQueue,它對應的執行緒池分別是 ScheduledThreadPool 和 SingleThreadScheduledExecutor,這兩種執行緒池的最大特點就是可以延遲執行任務,比如說一定時間後執行任務或是每隔一定的時間執行一次任務。DelayedWorkQueue 的特點是內部元素並不是按照放入的時間排序,而是會按照延遲的時間長短對任務進行排序,內部採用的是“堆”的資料結構。之所以執行緒池 ScheduledThreadPool 和 SingleThreadScheduledExecutor 選擇 DelayedWorkQueue,是因為它們本身正是基於時間執行任務的,而延遲佇列正好可以把任務按時間進行排序,方便任務的執行。
二 執行緒池介紹
FixedThreadPool(建固定核心數的執行緒池):定長的執行緒池,有核心執行緒,核心執行緒的即為最大的執行緒數量,沒有非核心執行緒,而且它們的執行緒數存活時間都是無限的,併發執行
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>()); }
對比 newSingleThreadPool,其實改變的也就是可以根據我們來自定義執行緒數的操作,比較相似。我們通過newFixedThreadPool(2)給它傳入了 2 個核心執行緒數
WorkStealingPool(建立一個具有搶佔式操作的執行緒池):JDK1.8 版本加入的一種執行緒池,stealing 翻譯為搶斷、竊取的意思,它實現的一個執行緒池和之前4種都不一樣,用的是 ForkJoinPool 類,建構函式程式碼如下
public static ExecutorService newWorkStealingPool(int parallelism) { return new ForkJoinPool (parallelism, ForkJoinPool.defaultForkJoinWorkerThreadFactory, null, true); }
parallelism => Runtime.getRuntime().availableProcessors() - 這是JVM可用的處理器數。
handler => ForkJoinPool.defaultForkJoinWorkerThreadFactory - 返回新執行緒的預設執行緒工廠。
asyncMode => true – 使其在aysnc模式下工作,併為分叉的任務設定FIFO順序,這些任務永遠不會從其工作佇列中加入
最明顯的用意就是它是一個並行的執行緒池,引數中傳入的是一個執行緒併發的數量,這裡和之前就有很明顯的區別,前面4種執行緒池都有核心執行緒數、最大執行緒數等等,而這就使用了一個併發執行緒數解決問題。從介紹中,還說明這個執行緒池不會保證任務的順序執行,也就是 WorkStealing 的意思,搶佔式的工作
SingleThreadPool(建立單核心的執行緒池):單核心執行緒池,最大執行緒也只有一個,這裡的時間為 0 意味著無限的生命,就不會被摧毀了,適用於有順序的任務的應用場景
public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())); }
CachedThreadPool(建立一個自動增長的執行緒池):可快取的執行緒池,該執行緒池中沒有核心執行緒,非核心執行緒的數量為Integer.max_value,就是無限大,當有需要時建立執行緒來執行任務,沒有需要時回收執行緒,預設60秒,適用於耗時少,任務量大的情況
public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); }
ScheduledThreadPool(建立一個按照計劃規定執行的執行緒池):週期性執行任務的執行緒池,按照某種特定的計劃執行執行緒中的任務,有核心執行緒,但也有非核心執行緒,非核心執行緒的大小也為無限大。適用於執行週期性的任務
public ScheduledThreadPoolExecutor(int corePoolSize) { super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS, new DelayedWorkQueue()); }
內部有一個延時的阻塞佇列來維護任務的進行,延時也就是在這裡進行的。我們把建立 newScheduledThreadPool 的程式碼放出來,這樣對比效果圖的話,顯得更加直觀。
// 引數2:延時的時長 scheduledExecutorService.schedule(th_all_1, 3000, TimeUnit.MILLISECONDS); scheduledExecutorService.schedule(th_all_2, 2000, TimeUnit.MILLISECONDS); scheduledExecutorService.schedule(th_all_3, 1000, TimeUnit.MILLISECONDS); scheduledExecutorService.schedule(th_all_4, 1500, TimeUnit.MILLISECONDS); scheduledExecutorService.schedule(th_all_5, 500, TimeUnit.MILLISECONDS);
FAQ:
1 執行緒池的核心執行緒會銷燬嗎?
當allowCoreThreadTimeOut手動設定為true或者執行的run方法丟擲異常,核心執行緒都會被銷燬,但是後者還是會建立新的執行緒稱呼來,前者則銷燬什麼都不做,關鍵在於allowCoreThreadTimeOut為true則下面程式碼直接返回,不在執行addWorker方法
2 執行緒池的執行流程?