Java定时调度任务的实现
有时候,我们希望程序在将来的某一时刻执行,也有想过让它可以重复执行多次!
于是,我们就需要实现定时调度功能。
在java里,由两个类来共同实现定时调度:java.util.Timer 和 java.util.TimerTask
Timer可以理解为有且只有一个后台线程对多个业务线程进行定时定频率调度
TimerTask可以理解为业务逻辑的编写
即:Timer按照一定的时间频率调度TimerTask里面的业务逻辑。
下面,通过实现怎么让程序在2秒后执行,来说明实现Timer调度的代码编写:
Timer timer=new Timer(); Calendar calendar =Calendar.getInstance(); SimpleDateFormat sf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println("当前时间是 "+sf.format(calendar.getTime())); timer.schedule(new TimerTask(){ public void run(){ Calendar calendar =Calendar.getInstance(); SimpleDateFormat sf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println("执行此次任务的时间是 "+sf.format(calendar.getTime())); } },2000);
可见,是通过实例化Timer,调用其的schedule方法来实现定时调度的。
schedule有以下四种形式:
schedule(task,time);
schedule(task,time,period);
schedule(task,delay);
schedule(task,delay,period);
其中,task是我们需要执行的任务,time是首次执行任务的时刻,period是执行一次task的时间间隔,delay是执行第一次任务前的延迟时间,单位均为毫秒。
那么最后就是编写task代码了
在这里,用一个内部类来说明,我们通过重写run方法的方式来编写自己的任务代码。
以上基本实现了定时定频率调度任务。
不过,有两个问题:
1.如果我们需要任务执行的时间,在当前时间之前,会发生什么?
2.如果我们任务的执行时间大于任务的执行间隔,会发生什么?
对于问题一,我们可以将上面的run方法稍加修改就可以知道了:
public void run(){ Calendar calendar =Calendar.getInstance(); SimpleDateFormat sf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); calendar.add(Calendar.SECOND, -1); System.out.println("执行此次任务的时间是 "+sf.format(calendar.getTime())); }
得出得结果是这样的:
当前时间是 2017-05-21 10:25:14
执行此次任务的时间是 2017-05-21 10:25:15
在我将程序中时间倒退了一秒的情况下,程序选择立刻执行并且还是会考虑延迟的。
对于问题二,也可以简单验证;
timer.schedule(new TimerTask(){
public void run(){ Calendar calendar =Calendar.getInstance(); SimpleDateFormat sf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("执行此次任务的时间是 "+sf.format(calendar.getTime())); } },1000,2000);
输出结果:
当前时间是 2017-05-21 10:31:05
执行此次任务的时间是 2017-05-21 10:31:06
执行此次任务的时间是 2017-05-21 10:31:09
执行此次任务的时间是 2017-05-21 10:31:12
是不是和想的一样,程序会相对于上一次执行完成的时间点开始执行,然后慢慢滞后。
讨论完了,schedule方法,其实Timer里面还有一个可以实现任务调度的方法,scheduleAtFixedRate,
scheduleAtFixedRate(task,time,period);
scheduleAtFixedRate(task,delay,period);
不考虑上面那两个问题的话,执行过程差不多,相对于那两种情况,因为scheduleAtFixedRate执行过程存在一定的并发性,在实际执行过程中小白感觉比较复杂,不讨论了。。。
最后简单说下,
Timer里面的其它重要方法:
cancel(),终止此计时器,丢弃所有当前已安排的任务,也可单独取消,如task1.cancel();
purge(),从此计时器的任务队列中移除所有已取消的任务,返回从队列中移除的任务数。
TimeTask里面的其它重要方法:
cancel(),取消当前TimeTask里的任务;
scheduledExecutionTime(),返回此任务最近实际执行的已安排执行的时间。