測試代碼
public class rejectHandler { public static void main(String[] arg){ Random random = new Random(); Executor executor = new ThreadPoolExecutor(2, // 線程池駐留線程數量 6, // 線程池最大線程數量 1, // 線程回收延時 SECONDS, // 線程回收延時單位 new LinkedBlockingQueue<Runnable>(10), // 大小爲10的緩衝區 Executors.defaultThreadFactory(), // 設置創建線程的工廠爲默認 new selfdefinedRejectionPolicy()); // 重寫的任務拒絕策略 while(true) { try { // 模擬任務線程 ((ThreadPoolExecutor) executor).submit(() -> { try { System.out.println("-------------------------"); System.out.println("Blocking Queue Size: "+((ThreadPoolExecutor) executor).getQueue().size()); System.out.println("Number of Threads: "+((ThreadPoolExecutor) executor).getPoolSize()); // long sleep = Math.abs((long)random.nextInt()/1000000); // Thread.sleep(sleep); // System.out.println("Having slept for " + sleep + "miliseconds."); Thread.sleep(3000); } catch (Exception e) { e.printStackTrace(); } }); Thread.sleep(500); }catch (InterruptedException e1){ e1.printStackTrace(); } } } }
代碼中我們啓了一個自己的線程池,第一個係數是線程池中駐留的線程數,如果系統的任務存在沒有任務的較長期的空閒時間,建議設爲0以節省系統資源;如果系統中來任務較爲頻繁建議設置一定數量的駐留線程。線程池最大線程數量爲這系統的最大容量,當任務到來頻繁時,可能需要增加線程數量以容納更多的任務執行。但是,系統資源是有限的,爲了是系統不至於崩潰,建議設置一個最大值以防止某些極限場景摧毀整個系統。當任務數量超過系統承受能力時,多餘的任務會被壓入一個緩衝隊列,如果你的系統時不時會有像DDOS一樣的任務潮,建議使用鏈式隊列(鏈表動態擴容)並將這個隊列設置得長一些。當任務實在多得連緩衝隊列都放不下時,會啓動拒絕策略,Executor提供的拒絕策略有四種,最常用的是Abort(拋異常)和Discard(丟棄)策略,這裏我們爲了統計被丟棄的任務數量,重寫了拒絕策略。
public class selfdefinedRejectionPolicy implements RejectedExecutionHandler { int count = 0; @Override public void rejectedExecution(Runnable r, ThreadPoolExecutor e){ count++; System.out.println(count + "tasks have been discarded!"); } }
將加載任務和處理任務的時間分別設置爲上面的時間(500ms加載一個任務,處理一個任務需要3s):
-------------------------
Blocking Queue Size: 9
Number of Threads: 5
37tasks have been discarded!
-------------------------
Blocking Queue Size: 9
Number of Threads: 5
-------------------------
Blocking Queue Size: 9
Number of Threads: 5
可以看到系統開啓了全部5個線程,隊列也基本佔滿。在3min中內丟棄了37個任務。這說明我們可能需要更大的線程容量了。
當然現實的情況肯定不是如此理想,可以使用真實的任務替換代碼中的sleep過程。