使用ScheduledExecutorService執行定時任務時必定要注意各類異常捕獲

近期一個項目有個定時任務阻塞住了,從日誌裏看沒有任何異常產生,但就是定時再也不執行了,進程還在,jstack看了下線程處於WAIT狀態,但就是再也不定時觸發。因而拿代碼分析了一下,代碼原理很簡單,拿ScheduledExecutorService.scheduleWithFixedDelay設定的定時任務,簡化後相似這樣:java

public class Application {
    private static ScheduledExecutorService timer = Executors.newScheduledThreadPool(2);
    public static void main(String[] args) {
        timer.scheduleWithFixedDelay(() -> {
            try {
                //此處執行任務
            } catch(Exception ex) {
                System.out.println(ex.getMessage());
            }
        }, 0, 1, TimeUnit.SECONDS);
    }
}

通常定時任務掛了,第一考慮的就是任務線程異常了,由於javadoc裏關於scheduleWithFixedDelay有這樣的警告:ide

使用ScheduledExecutorService執行定時任務時必定要注意各類異常捕獲

當有異常產生時,後續定時任務就停掉了。可是代碼裏已經考慮了異常狀況,作了try/catch,而且沒有輸出錯誤日誌,只好修改代碼嘗試跟蹤下線程執行結果:測試

public class Application {
    private static ScheduledExecutorService timer = Executors.newScheduledThreadPool(2);
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ScheduledFuture<?> handle = timer.scheduleWithFixedDelay(() -> {
            try {
                //此處執行任務
            } catch(Exception ex) {
                System.out.println(ex.getMessage());
            }
        }, 0, 1, TimeUnit.SECONDS);

        handle.get();    //若是線程執行異常,此處會拋出
    }
}

用ScheduledFuture跟蹤,上面的測試程序固然不會報錯,但在實際環境裏打印了下面的異常:大數據

Exception in thread "pool-1-thread-1" java.util.concurrent.ExecutionException: java.lang.OutOfMemoryError

這下搞清楚了,由於-Xmx參數不合理致使線程在處理某個大數據時拋出OOM,這個錯誤沒有被上面的try/catch捕獲,致使定時任務掛掉。所以使用ScheduledExecutorService時必定要注意考慮各類可能的異常,不過對於OOM,即便捕獲了能作的事也有限,但至少能夠保證定時任務能繼續,而且在日誌裏留下痕跡方便排查。線程

相關文章
相關標籤/搜索