從ExecutorService的內存溢出談談線程池


  之前寫的一個Sql轉發應用出現了內存溢出問題,經過排查發現是ExecutorService沒有正確的進行關閉。

  正常來說如果我們將ExecutorService設計成一個靜態變量,那么通常我們是不用去管理其是否關閉的,我們只需要對其本身的線程進行維護操作,ExecutorService對象不用我們顯示的進行維護操作。但是維護靜態線程池對象的不足之處在於,不好去界定池量級的大小,如果太小會導致線程過多的時候線程運行得不到保證,如果過大則通常線程執行時是對內存的一種浪費。所以在調用頻率不高的時候,我們往往會在一次調用的時候創建一個ExecutorService,用這個來進行線程池的管理,那么這里就出現了我們遇到的問題,那就是這個ExecutorService其實是需要手動進行關閉的。

 

 

   上圖中ExecutorService就沒有正確的關閉。

  為什么ExecutorService不會自己進行回收呢,我們通過對其API的閱讀可以得到答案,若是想要ExecutorService完全關閉需要同時滿足三個條件:

  1.線程池中沒有正在執行的task任務

  2.線程池中沒有等待執行的task任務

  3.無法再提交任務到ExecutorService

  顯然,如果我們不進行手動關閉的話,第三個條件將無法滿足,導致無法其內存無法被回收,而下一次的調用又繼續進行了線程池的創建,這樣內存迅速的上升,最后導致了OOM。

  那么知道了問題的原因,解決方法其實就比較簡單了,我們在使用完之后再調用一個shutdown或者shutdownNow,讓線程池狀態變成不再能接受線程任務就行了。

  但是這個時候就有了新的問題,如果某個線程阻塞,一直無法關閉,shutdown方法也不能完成自己的使命,但是如果使用shutdownNow方法的話,就會出現關閉的時候還有線程任務沒有完成。這個時候要怎么合理的進行線程任務的關閉呢。

  這個時候我們可以設定一個最大超時時間,如果執行shutdown之后經過超時時間還有任務沒有結束,那我們就用shutdownNow方法來幫他們上路。

 

 

  


免責聲明!

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



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