線程池(Thread Pool) 是並行執行任務收集的實用工具。隨著CPU 引入適合於應用程序並行化的多核體系結構,線程池的作用正日益顯現。通過ThreadPoolExecutor類及其他輔助類,Java 5 引入了這一框架,作為新的並發支持部分。
ThreadPoolExecutor框架靈活且功能強大,它支持特定於用戶的配置並提供了相關的掛鉤(hook)和飽和策略來處理滿隊列
Java線程池會將提交的任務先置於工作隊列中,在從工作隊列中獲取(SynchronousQueue直接由生產者提交給工作線程)。那麼工作隊列就有兩種實現策略:無界隊列和有界隊列。無界隊列不存在飽和的問題,但是其問題是當請求持續高負載的話,任務會無腦的加入工作隊列,那麼很可能導致內存等資源溢出或者耗盡。而有界隊列不會帶來高負載導致的內存耗盡的問題,但是有引發工作隊列已滿情況下,新提交的任務如何管理的難題,這就是線程池工作隊列飽和策略要解決的問題。
飽和策略分為:Abort 策略, CallerRuns 策略,Discard策略,DiscardOlds策略。
為了更好的理解,我編寫一個小的例子。
package concurrency.pool;import java.util.concurrent.LinkedBlockingDeque;import java.util.concurrent.RejectedExecutionHandler;import java.util.concurrent.ThreadPoolExecutor;import java.util.concurrent.TimeUnit;public class SaturationPolicy {/** * 線程池工作隊列已滿時,在不同飽和策略下表現* @param handler 線程池工作隊列飽和策略*/public static void policy(RejectedExecutionHandler handler){//基本線程2個,最大線程數為3,工作隊列容量為5ThreadPoolExecutor exec = new ThreadPoolExecutor(2,3,0l, TimeUnit.MILLISECONDS,new LinkedBlockingDeque<>(5));if (handler != null){exec.setRejectedExecutionHandler(handler);//設置飽和策略}for (int i = 0; i < 10; i++) {exec.submit(new Task());//提交任務}exec.shutdown();}public static void main(String[] args) {// policy(new ThreadPoolExecutor.AbortPolicy());// policy((new ThreadPoolExecutor.CallerRunsPolicy()));// policy(new ThreadPoolExecutor.DiscardPolicy());// policy(new ThreadPoolExecutor.DiscardOldestPolicy());}//自定義任務static class Task implements Runnable {private static int count = 0;private int id = 0;//任務標識public Task() {id = ++count;}@Override public void run() {try {TimeUnit.SECONDS.sleep(3);//休眠3秒}catch (InterruptedException e) {System.err.println("線程被中斷" + e.getMessage());}System.out.println(" 任務:" + id + "/t 工作線程: "+ Thread.currentThread().getName() + " 執行完畢");}}}當工作隊列滿了,不同策略的處理方式為:
1.Abort策略:默認策略,新任務提交時直接拋出未檢查的異常RejectedExecutionException,該異常可由調用者捕獲。
在主函數中添加如下代碼:
policy(new ThreadPoolExecutor.AbortPolicy());
運行結果為:
程序拋出了RejectedExecutionException,並且一共運行了8個任務(線程池開始能運行3個任務,工作隊列中存儲5個隊列)。當工作隊列滿了的時候,直接拋出了異常,而且JVM一直不退出(我現在也不知道什麼原因)。我們可以看到執行任務的線程全是線程池中的線程。
2.CallerRuns策略:為調節機制,既不拋棄任務也不拋出異常,而是將某些任務回退到調用者。不會在線程池的線程中執行新的任務,而是在調用exector的線程中運行新的任務。
在主函數運行:
policy((new ThreadPoolExecutor.CallerRunsPolicy()));
運行結果
所有的任務都被運行,且有2(10 - 3 -5)個任務是在main線程中執行成功的,8個任務在線程池中的線程執行的。
3.Discard策略:新提交的任務被拋棄。
在main函數中運行
policy(new ThreadPoolExecutor.DiscardPolicy());
通過上面的結果可以顯示:沒有異常拋出,後面提交的2個新任務被拋棄,只處理了前8(3+5)個任務,JVM退出。
4.DiscardOldest策略:隊列的是“隊頭”的任務,然後嘗試提交新的任務。 (不適合工作隊列為優先隊列場景)
在main函數中運行如下方法
policy(new ThreadPoolExecutor.DiscardOldestPolicy());
運行結果:一共運行8個任務,程序結束,後面添加的任務9,任務10被執行了,而前面的任務3,任務4被丟棄。
總結
以上就是本文關於java線程池工作隊列飽和策略代碼示例的全部內容,希望對大家有所幫助。如有不足之處,歡迎留言指出。感謝朋友們對本站的支持。