上一篇博文《任务调度(一)——jdk自带的Timer》中,简单介绍了一下Timer,本文将分享一下如何动态修改Timer制定的计划。
先上代码:
package com.tgb.ccl.schema.dynamic; import java.util.Date; /** * 可动态修改的任务 * * @author arron * @date 2015年5月9日 下午1:52:15 * @version 1.0 */ public class DynamicTimerTask extends java.util.TimerTask { @Override public void run() { System.out.println("---------start--------"); Date d = new Date(); for(int i=0;i<2;i++){ try { Thread.sleep(1000); System.out.println("已执行【"+(i+1)+"】秒钟,at: "+d.toLocaleString()); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("本次任务调度结束,at: "+new Date().toLocaleString()); System.out.println("----------------------------------------------"); } }
package com.tgb.ccl.schema.dynamic; import java.util.Calendar; import java.util.Date; import java.util.Timer; /** * 任务调度管理器 * * @author arron * @date 2015年5月9日 下午1:57:19 * @version 1.0 */ public class DynamicTaskManager { private static final long PERIOD = 5 * 1000;// 5秒钟 /** * 单例对象 */ private static DynamicTaskManager taskManager = null; /** * 时间调度对象 */ private static Timer timer = new Timer(); /** * 任务 */ private static DynamicTimerTask task = null; static { taskManager = new DynamicTaskManager(); } public static DynamicTaskManager getInstance(){ if(taskManager==null){ taskManager = new DynamicTaskManager(); } return taskManager; } public DynamicTaskManager() { } @SuppressWarnings("deprecation") public void startTask(Date startTime, long period){ System.out.println("设置启动时间: "+startTime.toLocaleString()); //如果当前时间超过了设定时间,会立即执行一次 task = new DynamicTimerTask(); timer.schedule(task, startTime,period); } /** * 启动定时器 */ public void start() { //启动任务,10点40启动任务 start(DateUtils.bookTime(10,40,0)); } /** * 启动定时器 */ public void start(long preiod) { //启动任务,10点40启动任务 start(DateUtils.bookTime(10,40,0),preiod); } /** * 启动定时器 */ public void start(Date startTime) { start(startTime,PERIOD); } /** * 启动定时器 */ public void start(Date startTime,long preiod) { startTask(startTime,preiod); } /** * 重新启动 */ public void restart() { clean(); start(); } /** * 清空timer */ public void clean() { if(task != null){ task.cancel(); } timer.purge(); } /** * 停止任务 */ public void stop(){ System.out.println("--------任务正在停止---------"); clean(); System.out.println("---------任务已停止----------"); } static class DateUtils{ /** * 增加或减少天数 * * @param date * @param CalendarFlag * 取值 Calendar.DAY_OF_MONTH, Calendar.HOUR_OF_DAY, * Calendar.MINUTE,Calendar.SECOND,Calendar.MILLISECOND * @param num * @return */ public static Date addDay(Date date, int CalendarFlag, int num) { Calendar startDT = Calendar.getInstance(); startDT.setTime(date); startDT.add(CalendarFlag, num); return startDT.getTime(); } /** * 设定时间 * * @param hour * @param minute * @param second * @return */ public static Date bookTime(int hour, int minute, int second) { Calendar calendar = Calendar.getInstance(); calendar.set(Calendar.HOUR_OF_DAY, hour); calendar.set(Calendar.MINUTE, minute); calendar.set(Calendar.SECOND, second); Date date = calendar.getTime(); return date; } } @SuppressWarnings("deprecation") public static void main(String[] args) { DynamicTaskManager manager = DynamicTaskManager.getInstance(); //启动任务,会立即执行一次,2s时执行完毕,5s时第二次执行,7s时第二次执行完毕 manager.start(); for(int i=0;i<8;i++){ try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } //8s时,stop原任务,动态更改启动时间 manager.stop(); System.out.println("当前时间:"+new Date().toLocaleString()); System.out.println("修改原计划,5s后重新执行"); //5s后再启动,即13s时再启动 manager.start(DateUtils.addDay(new Date(), Calendar.SECOND, 5)); } }
运行结果如下:
从结果中,我们可以看到,原先的计划是在14:46:40时开始,第二次是在14:46:45,每次执行2s中,也就是说如果不更改任务计划,那么任务将总会在0s或者5s的时候执行。但是我在main方法中,将原来的任务关闭,然后修改了启动时间,当前时间5s后启动新任务。当前时间为14:46:48,5s后执行了新计划。这就完成了任务的动态修改。
首先说一下,如果关闭任务,stop方法完成了这个功能。要想任务不继续执行,必须将task的状态设置为cancel,然后调用timer的purge方法,将队列里的所有状态为cancel的task移除。这样就算到了执行时间,由于task已经移除,也就不会再执行了。如果使用了timer的cancel()方法,那么会将timer中所有的task全部移除掉。这点要注意一下。
其实在项目中使用时,要比这个还要简单。直接修改startTask()方法,启动时间和间隔都是从数据库中取就ok了。只要想更改计划时,先配置好启动时间和间隔,然后自己写一个restart的方法,调用clean和startTask方法即可。
有人问我Timer和Quartz框架的区别。那我就说一下我的理解。Timer毕竟是jdk自带的简易的任务调度工具类,跟Quartz比肯定是鸟枪与大炮的差距。Quartz的配置规则更加强大,更能满足我们的复杂需求,还允许多线程,这是Timer所比不了的。如果你就需要特别简单的任务调度,那么我觉得完全没有必要用Quartz。杀鸡焉用牛刀?!如果你的业务场景比较复杂,比如要求每个月的第4周的最后一个工作日要执行结算工资,如果最后一天是周六,就会向前提一天,在周五执行。这样的场景用Quartz要比Timer简单吧。
不过具体用什么,还需要看项目。没有什么谁更牛,只有谁更适合。