背景
系統突然error飚高,不停full gc。
最後發現是因為調用的外部jar包中方法觸發bug導緻死循環,不斷産生新對象,導緻記憶體大量占用無法釋放,最終jvm記憶體回收機制崩潰。
解決思路
服務一旦進入死循環,對應線程一直處于running狀态,難以通過該線程自己計時中斷。
對于無法完全放心的第三方jar包方法,可以選擇開子線程處理,并對線程加以監控,當逾時時及時中斷子線程并傳回。
兩種實作思路:
思路一: 通過futuretask
future在設定的時間逾時後會抛出timeout異常,通常做法是捕獲異常後執行future.cancel()方法。但cancel方法實際是調用線程的interrupt方法,給線程樹立interrupt status,并不能中斷死循環的子線程。
future沒有提供能夠直接停止子線程的方法(也許是因為線程的stop方法可能産生不良後果)
是以這裡可以參照futuretask源碼,建立一個myfuturetask類,改寫或建立一個類似cancel的方法,調用線程的stop方法。
demo中的myfuturetask類參考cancel方法,建立了myfuturetask.stop方法,調用子線程的stop方法來中止子線程。
思路二:通過countdownlatch
主線程建立可能出現死循環的子線程時設立countdownlatch值為1,子線程邏輯中當處理完畢執行countdownlatch減1。這樣主線程可以看到子線程是執行完畢還是逾時,如果逾時或子線程已處理完畢,在主線程中執行子線程的stop方法中止子線程。
demo代碼
思路一:
思路二: