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>