java多線程 ThreadPoolExecutor 策略的坑


   無論是使用jdk的線程池ThreadPoolExecutor 還是spring的線程池ThreadPoolTaskExecutor 都會使用到一個阻塞隊列來進行存儲線程任務。

   當線程不夠用時,則將后續的任務暫存到 阻塞隊列中,等待有空閑線程來進行。

  當這個阻塞隊列滿了的時候,會出現兩種情況

   正在運行的線程數量小於 maximumPoolSize,那么還是要創建線程運行這個任務;

   正在運行的線程數量大於或等於 maximumPoolSize,那么線程池會通過一個策略進行對后續的任務進行處理。

 

四種策略

ThreadPoolExecutor.AbortPolicy()  拋出java.util.concurrent.RejectedExecutionException異常 
ThreadPoolExecutor.CallerRunsPolicy() 重試添加當前的任務,他會自動重復調用execute()方法 
ThreadPoolExecutor.DiscardOldestPolicy() 拋棄舊的任務 
ThreadPoolExecutor.DiscardPolicy() 拋棄當前的任務 

其他很容易看出來,最近踩了一個ThreadPoolExecutor.CallerRunsPolicy()的坑。

情景是這樣的:我需要通過線程進行創建長連接,當開啟了15個線程的是,線程池最大即達到了maximumPoolSize的數量的時候,繼續增大請求量,會無緣無故的多出來

一個長連接,由於有負載均衡,導致了很多請求無法從長連接中得到。

經過很長時間的測試,最終發現了是ThreadPoolExecutor.CallerRunsPolicy()策略導致的。

這個測試是當你的線程數達到最大,阻塞隊列也滿了的時候,之后的任務會強制先執行,但是沒有了線程誰來執行呢,這個策略會強制中斷主線程進行執行這個任務。

即是說,當我的量上來,線程池不夠用的時候,中斷了我的主線程,主線程沒有長連接,就建立了一個新的長連接,那邊進行了負載均衡,但是這邊不會在進行主線程了,

導致很多請求接收不到。

假設隊列大小為 10,corePoolSize 為 3,maximumPoolSize 為 6,那么當加入 20 個任務時,執行的順序就是這樣的:首先執行任務 1、2、3,然后任務 4~13 被放入隊列。這時候隊列滿了,任務 14、15、16 會被馬上執行,最終順序是:1、2、3、14、15、16、4、5、6、7、8、9、10、11、12、13。

 

踩坑完畢

最終做法:

換成ThreadPoolExecutor.DiscardPolicy()策略,還是從已經建立的連接中進行 的到請求,不要繼續創建連接。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM