1,java.util.Timer和TimerTask是JDK1.3自带的定时任务实现类,使用非常简单,不过由于依赖系统时间,在时间跳变的情况下,执行会出现一些变化。如果时间向后(未来方向)修改,不影响任务执行,但如果向前(过去方向)修改,取决于时间调整的幅度,定时任务可能延迟很久才能回复正常,这在程序运行过程中,可能并不是我们所期望的的,对于一些依赖定时任务执行的关键任务 ,可能导致严重后果。
/** * @param args */ public static void main(String[] args) { TimerTask task = new TimerTask() { public void run() { System.out.println("Timer task execute " + ++times + " at " + new Date() + ",expected executing at " + new Date(this.scheduledExecutionTime())); } }; Timer tm = new Timer(); /** * Timer基于系统时间是准确的前提;执行过程中: * 如果系统时间被往后修改,根据Timer类mainLoop方法中taskFired = (executionTime<=currentTime)的判断,程序还是会继续执行,间隔也不受影响 * 如果系统时间被往前修改,仍然是根据上面所述判断,则下一次执行时间会被延后,后面恢复正常 */ tm.schedule(task, new Date(), 2 * 60 * 1000); }
2,自打JDK1.5开始,我们可以选择ScheduledExecutorService来替代Timer执行定时任务。ScheduledExecutorService并不是基于绝对的时间和周期,而是基于时间延迟和周期,这样当出现时间跳变(网络延迟/时间服务器同步/人工干预修改时间),定时任务仍然按照原来的时间间隔执行。
public class JdkScheduledExecutorService { private static int times = 0; private static long nextExecuteTime = new Date().getTime(); /** * @param args */ public static void main(String[] args) { TimerTask task = new TimerTask() { public void run() { nextExecuteTime += 2 * 60 * 1000; System.out.println("Timer task execute " + ++times + " at " + new Date() + ",expected executing at " + new Date(nextExecuteTime)); } }; ScheduledExecutorService service = Executors.newScheduledThreadPool(1); service.scheduleAtFixedRate(task, 0, 2, TimeUnit.MINUTES); } }
上述两段代码可在运行时,分别先后将时间向后修改,观察控制台输出效果,再向前修改并观察效果。
Spring的Schedule支持多种定时任务实现,具体可参考http://static.springsource.org/spring/docs/3.0.x/reference/scheduling.html#threadPoolTaskExecutor
使用上述Timer时,配置如下(已过时,建议不要再使用)
<context:component-scan base-package="com.bryan.schedule" use-default-filters="false"> <context:include-filter type="regex" expression="com.bryan.schedule.SpringTimer.*"/> </context:component-scan> <bean id="testTask" class="org.springframework.scheduling.timer.ScheduledTimerTask"> <property name="timerTask"> <ref bean ="timer"/> </property> <property name="period"> <value>120000</value> </property> <property name="delay"> <value>0</value> </property> </bean> <bean class="org.springframework.scheduling.timer.TimerFactoryBean"> <property name="scheduledTimerTasks"> <list> <ref local="testTask" /> </list> </property> </bean>
使用ScheduledExecutorService时,配置如下
<bean id="testTask" class="org.springframework.scheduling.concurrent.ScheduledExecutorTask"> <property name="runnable"> <ref bean ="timer"/> </property> <property name="period"> <value>120000</value> </property> <property name="delay"> <value>0</value> </property> <property name="fixedRate"> <value>true</value> </property> </bean> <bean class="org.springframework.scheduling.concurrent.ScheduledExecutorFactoryBean"> <property name="scheduledExecutorTasks"> <list> <ref local="testTask" /> </list> </property> </bean>