在java多線程編程中,java.util.concurrent.RejectedExecutionException 異常時常困擾開發者。該異常通常指示線程池已無法處理新的任務,這并非總是線程池配置問題,而是多種因素綜合作用的結果。本文將通過一個案例,深入剖析該異常的成因并提供有效的解決策略。
案例分析:
程序拋出 RejectedExecutionException 異常,異常信息顯示線程池狀態為:運行中,池大小為160,活動線程數為160,排隊任務數為10000,已完成任務數為588179。這表明所有160個線程均處于繁忙狀態,等待隊列中積壓了大量任務。已完成任務數量巨大,暗示問題并非偶然,而是長期累積的結果。線程池配置使用了 AbortPolicy 拒絕策略,參數為 new ThreadPoolExecutor(processNum * 10, processNum * 10, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue(10000), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy()),核心線程數和最大線程數均為 processNum * 10,等待隊列長度為10000。服務器為8核16線程。
立即學習“Java免費學習筆記(深入)”;
異常根源:
RejectedExecutionException 異常的核心原因在于:任務提交速度遠超線程池處理能力。即使線程池配置了較大的核心線程數、最大線程數和等待隊列,當任務生成速度過快時,等待隊列最終會被填滿。由于使用了 AbortPolicy 拒絕策略,任何新的任務都會被拒絕并拋出異常。
解決方案:
解決此問題需要多方面入手:
-
理解線程池核心參數: 核心線程數 (corePoolSize)、最大線程數 (maximumPoolSize)、等待隊列 (BlockingQueue
workQueue) 和拒絕策略 (RejectedExecutionHandler handler)。 線程池工作流程:先嘗試使用核心線程;核心線程滿則放入等待隊列;等待隊列滿且線程數小于最大線程數則創建新線程;線程數達到最大線程數則觸發拒絕策略。 -
調整線程池參數: 當前配置中,核心線程數和最大線程數相同,等待隊列長度為10000??紤]到服務器為8核16線程,建議調整核心線程數和最大線程數,使其更貼合實際CPU資源和任務處理能力。同時,需謹慎評估等待隊列長度,過大的隊列可能導致內存溢出。
-
優化拒絕策略: AbortPolicy 策略直接拋出異常,不適用于生產環境。建議考慮以下替代策略:
- CallerRunsPolicy:提交任務的線程自行執行,降低任務提交速率。
- DiscardPolicy:直接丟棄新任務。
- DiscardOldestPolicy:丟棄等待隊列中最舊的任務。
選擇合適的拒絕策略取決于具體業務需求和容錯要求。 合理的拒絕策略能有效控制線程池資源使用,避免 RejectedExecutionException 異常。
通過以上分析和調整,可以有效預防和解決java線程池的拒絕執行異常,確保應用程序穩定運行。