執行緒池的拒絕策略及常見執行緒池

2022-10-07 12:27:11 字數 4324 閱讀 8118

第一種拒絕策略是 abortpolicy,這種拒絕策略在拒絕任務時,會直接丟擲乙個型別為 rejectedexecutionexception 的 runtimeexception,讓你感知到任務被拒絕了,於是你便可以根據業務邏輯選擇重試或者放棄提交等策略。

第二種拒絕策略是 discardpolicy,這種拒絕策略正如它的名字所描述的一樣,當新任務被提交後直接被丟棄掉,也不會給你任何的通知,相對而言存在一定的風險,因為我們提交的時候根本不知道這個任務會被丟棄,可能造成資料丟失。

第三種拒絕策略是 discardoldestpolicy,如果執行緒池沒被關閉且沒有能力執行,則會丟棄任務佇列中的頭結點,通常是存活時間最長的任務,這種策略與第二種不同之處在於它丟棄的不是最新提交的,而是佇列中存活時間最長的,這樣就可以騰出空間給新提交的任務,但同理它也存在一定的資料丟失風險。

第四種拒絕策略是 callerrunspolicy,相對而言它就比較完善了,當有新任務提交後,如果執行緒池沒被關閉且沒有能力執行,則把這個任務交於提交任務的執行緒執行,也就是誰提交任務,誰就負責執行任務。這樣做主要有兩點好處。

執行緒池佇列

建立方式

適用場景

fixedthreadpool

linkedblockingqueue

threadpoolexecutor

singlethreadexecutor

linkedblockingqueue

threadpoolexecutor

cachedthreadpool

synchronousqueue

threadpoolexecutor

scheduledthreadpoolexecutor

delayedworkqueue

scheduledthreadpoolexecutor

singlethreadscheduledexecutor

delayedworkqueue

scheduledthreadpoolexecutor

forkjoinpool

fixedthreadpool

cachedthreadpool

可以稱作可快取執行緒池,它的特點在於執行緒數是幾乎可以無限增加的(實際最大可以達到 integer.max_value,為 2^31-1,這個數非常大,所以基本不可能達到),而當執行緒閒置時還可以對執行緒進行**。也就是說該執行緒池的執行緒數量不是固定不變的,當然它也有乙個用於儲存提交任務的佇列,但這個佇列是 synchronousqueue,佇列的容量為0,實際不儲存任何任務,它只負責對任務進行中轉和傳遞,所以效率比較高。

支援定時或週期性執行任務。比如每隔 10 秒鐘執行一次任務,而實現這種功能的方法主要有 3 種,如**所示:

scheduledexecutorservice service = executors.newscheduledthreadpool(10);

service.schedule(new task(), 10, timeunit.seconds);

service.scheduleatfixedrate(new task(), 10, 10, timeunit.seconds);

service.schedulewithfixeddelay(new task(), 10, 10, timeunit.seconds);

3種方法的區別

singlethreadexecutor

使用唯一的執行緒去執行任務,原理和 fixedthreadpool 是一樣的,只不過這裡執行緒只有乙個,如果執行緒在執行任務的過程中發生異常,執行緒池也會重新建立乙個執行緒來執行後續的任務。這種執行緒池由於只有乙個執行緒,所以非常適合用於所有任務都需要按被提交的順序依次執行的場景,而前幾種執行緒池不一定能夠保障任務的執行順序等於被提交的順序,因為它們是多執行緒並行執行的。

singlethreadscheduledexecutor

第二個執行緒池 cachedthreadpool 的核心執行緒數是 0,而它的最大執行緒數是 integer 的最大值,執行緒數一般是達不到這麼多的,所以如果任務特別多且耗時的話,cachedthreadpool 就會建立非常多的執行緒來應對。

如圖所示,我們有乙個 task,這個 task 可以產生三個子任務,三個子任務並行執行完畢後將結果彙總給 result,比如說主任務需要執行非常繁重的計算任務,我們就可以把計算拆分成三個部分,這三個部分是互不影響相互獨立的,這樣就可以利用 cpu 的多核優勢,平行計算,然後將結果進行彙總。這裡面主要涉及兩個步驟,第一步是拆分也就是 fork,第二步是彙總也就是 join,到這裡你應該已經了解到 forkjoinpool 執行緒池名字的由來了

典型的斐波拉契數列

數列的特點就是後一項的結果等於前兩項的和,第 0 項是 0,第 1 項是 1,那麼第 2 項就是 0+1=1,以此類推。我們通常通過遞迴方式實現

if (n <= 1)  else
使用forkjointask子類recursivetask實現

public class fibonacci extends recursivetask

@override

public integer compute()

fibonacci f1 = new fibonacci(n - 1);

f1.fork();

fibonacci f2 = new fibonacci(n - 2);

f2.fork();

return f1.join() + f2.join();

}}

public class forkjoinpool01 

}}

結果

011

2358

1321

34

countedcompleter

forkjoinpool採用分治策略fork join拆分任務然後合併結果

阻塞佇列

執行緒池佇列

fixedthreadpool

linkedblockingqueue

singlethreadexecutor

linkedblockingqueue

cachedthreadpool

synchrouousqueue

schedulethreadpool

delayedworkqueue

singlethreadscheduledexecutor

delayedworkqueue

linkedblockingqueue

對於 fixedthreadpool 和 singlethreadexector 而言,它們使用的阻塞佇列是容量為 integer.max_value 的 linkedblockingqueue,可以認為是無界佇列。由於 fixedthreadpool 執行緒池的執行緒數是固定的,所以沒有辦法增加特別多的執行緒來處理任務,這時就需要 linkedblockingqueue 這樣乙個沒有容量限制的阻塞佇列來存放任務。這裡需要注意,由於執行緒池的任務佇列永遠不會放滿,所以執行緒池只會建立核心執行緒數量的執行緒,所以此時的最大執行緒數對執行緒池來說沒有意義,因為並不會觸發生成多於核心執行緒數的執行緒。

synchrouousqueue

第二種阻塞佇列是 synchronousqueue,對應的執行緒池是 cachedthreadpool。執行緒池 cachedthreadpool 的最大執行緒數是 integer 的最大值,可以理解為執行緒數是可以無限擴充套件的。cachedthreadpool 和上一種執行緒池 fixedthreadpool 的情況恰恰相反,fixedthreadpool 的情況是阻塞佇列的容量是無限的,而這裡 cachedthreadpool 是執行緒數可以無限擴充套件,所以 cachedthreadpool 執行緒池並不需要乙個任務佇列來儲存任務,因為一旦有任務被提交就直接**給執行緒或者建立新執行緒來執行,而不需要另外儲存它們。

delayedworkqueue

第三種阻塞佇列是delayedworkqueue,它對應的執行緒池分別是 scheduledthreadpool 和 singlethreadscheduledexecutor,這兩種執行緒池的最大特點就是可以延遲執行任務,比如說一定時間後執行任務或是每隔一定的時間執行一次任務。delayedworkqueue 的特點是內部元素並不是按照放入的時間排序,而是會按照延遲的時間長短對任務進行排序,內部採用的是「堆」的資料結構。之所以執行緒池 scheduledthreadpool 和 singlethreadscheduledexecutor 選擇 delayedworkqueue,是因為它們本身正是基於時間執行任務的,而延遲佇列正好可以把任務按時間進行排序,方便任務的執行。

執行緒池拒絕策略

手寫執行緒池拒絕策略 執行緒池的引數 預設策略 預設 拒絕策略 丟擲異常 程式崩潰 第二種策略 執行緒從哪來 回哪去 這個 用力 將 executorservice exec newthreadpoolexecutor 1 2,30 timeunit.microseconds,newarrayblo...

執行緒池拒絕策略

public void rejectedexecution runnable r,threadpoolexecutor e 丟擲異常表明哪個任務在哪個執行緒池中執行失敗了 public void rejectedexecution runnable r,threadpoolexecutor e 如果...

執行緒池的拒絕策略

今天我自己整理了一下threadpoolexector的最後乙個引數 拒絕策略 當新到的任務數量已經超過了系統實際能夠承載的能力時,就會觸發拒絕策略,這是系統超負荷執行的補救措施具體以下3個方面 執行緒池有乙個任務佇列,用於快取所有待處理的任務,一旦開始處理這些任務,這些任務將從任務佇列中刪除,在任...