使用ScheduledExecutorService执行定时任务时一定要注意各种异常捕获

近期一个项目有个定时任务阻塞住了,从日志里看没有任何异常产生,但就是定时不再执行了,进程还在,jstack看了下线程处于WAIT状态,但就是不再定时触发。于是拿代码分析了一下,代码原理很简单,拿ScheduledExecutorService.scheduleWithFixedDelay设定的定时任务,简化后类似这样:

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有这样的警告:

 

当有异常产生时,后续定时任务就停掉了。但是代码里已经考虑了异常情况,做了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,即使捕获了能做的事也有限,但至少可以保证定时任务能继续,并且在日志里留下痕迹方便排查。

 

posted on 2020-10-28 13:30  BoyTNT  阅读(1024)  评论(0编辑  收藏  举报

导航