使用ScheduledThreadPoolExecutor需要注意的问题

319 查看

玩过linux系统的同学,应该都知道cron是一个linux下的定时执行工具,一些重要的任务的定时执行可以通过cron来实现,例如每天凌晨1点备份数据等。在JAVA WEB开发中,我们也经常需要用到定时执行任务的功能,JDK提供了Timer类与ScheduledThreadPoolExecutor类实现这个定时功能。但在使用这两个类的时候,要特别注意异常处理问题。以下是一个模拟程序:

public class ScheduledThreadPoolExecutorTest {
    public static void main(String[] args) {
        ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(1);
        BusinessTask task = new BusinessTask();
        //1秒后开始执行任务,以后每隔2秒执行一次
        executorService.scheduleWithFixedDelay(task, 1000, 2000,TimeUnit.MILLISECONDS);
    }

    private static class BusinessTask implements Runnable{
        @Override
        public void run() { 
            System.out.println("任务开始...");
            //doBusiness();
            System.out.println("任务结束...");
        }
    }
}

程序输出结果跟相像中一样:

任务开始...
任务结束...
任务开始...
任务结束...

可是执行了一段时间后,发现定时任务不再执行了,去查看后台打印的日志,原来在doBusiness()方法中抛出了异常。为什么doBusiness()抛出异常就会中止定时任务的执行呢?去查看JDK的ScheduledThreadPoolExecutor.scheduleWithFixedDelay(Runnable command,long initialDelay,long delay,TimeUnit unit)的方法说明:

Creates and executes a periodic action that becomes enabled first after the given initial delay, and subsequently with the given delay between the termination of one execution and the commencement of the next. If any execution of the task encounters an exception, subsequent executions are suppressed. Otherwise, the task will only terminate via cancellation or termination of the executor.

这段话翻译成中文是:

创建并执行一个在给定初始延迟后首次启用的定期操作,随后,在每一次执行终止和下一次执行开始之间都存在给定的延迟。如果任务的任一执行遇到异常,就会取消后续执行。否则,只能通过执行程序的取消或终止方法来终止该任务。

看到这里,我们明白了原因,这样就需要把doBusiness()方法的所有可能异常捕获,才能保证定时任务继续执行。把代码改成这样:

public class ScheduledThreadPoolExecutorTest {
    public static void main(String[] args) {
        ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(1);
        BusinessTask task = new BusinessTask();
        //1秒后开始执行任务,以后每隔2秒执行一次
        executorService.scheduleWithFixedDelay(task, 1000, 2000,TimeUnit.MILLISECONDS);
    }

    private static class BusinessTask implements Runnable{
        @Override
        public void run() { 
            //捕获所有的异常,保证定时任务能够继续执行
            try{
                System.out.println("任务开始...");
                //doBusiness();
                System.out.println("任务结束...");
            }catch (Throwable e) {
                // donothing
            }
        }
    }
}

其实,在JAVAWEB开发中,执行定时任务有一个更好的选择:Quartz

这个开源库提供了丰富的作业调度集,有兴趣的同学可以到官方网站中学习一下其用法。


2018 - 知识虫 - 我的知识库 渝ICP备16002641号-2

渝公网安备 50010702501581号