本文已参与「新人创作礼」活动,一起开启掘金创作之路。
什么是定时任务调度?
基于给定的时间点、给定的时间间隔或给定的执行次数自动执行的任务。
在java中的定时调度工具:Timer,Quartz。实际中的大多数的定时任务都可以由Timer实现,但是和Quartz相比功能还是稍弱一点。
Timer和Quartz的区别:
1.出身不同:
Timer是由jdk提供,调用方式简单粗暴,不需要别的jar的支持。
Quartz是源于OpenSynmphony提供的强大的开源任务调度框架,并非jdk自带。需要引入jar。
2.能力区别:
主要体现在对时间的控制上。Quartz对时间的控制功能远比Timer强大。
3.底层功能:
Timer只需要一个后台线程去完成定时任务。Quartz后台拥有一个线程池去执行定时任务,可以有多个线程去执行任务。
Timer简介:
Timer是java.util包下的一个类。有且仅有一个后台线程对多个业务线程进行定时定频率的调度。Timer可以理解为是一个后台执行的线程,TimerTask是业务线程,通过Timer定时调用TimerTask来实现对业务的定时调用。
Timer类由四部分组成:
Timer是主类,包含两个属性,一个是thread,即后台线程。另一个事队列,队列里面是TimerTask,TimerTask中的run方法里定义了要定时执行的业务逻辑。后台线程Thread定时定频率地执行队列中的TimerTask中的run方法来实现定时任务调度。
TimerTask的cancel():取消当前TimerTask里的任务。
scheduleExecutionTime():返回此任务最近实际执行的已安排执行的时间。(也就是离现在最近一次安排的任务的执行时间)
Timer的cancel():终止此计时器,丢弃所有当前已安排的任务。
purge():从此计时器的任务队列中移除所有已取消的任务。返回值是从队列中移除的任务数。
Schedule()与scheduleAtFixedRate()都是表示调度任务的方法,他们的区别是:
场景一:首次计划执行时间早于当前时间(如当前时间是00:06,首次计划执行时间是00:00)
schedule():第一次应当执行的时间已经过去了,那就从当前时间开始第一次执行,后面的执行时间按照第一次实际执行完成的时间点进行计算。
scheduledAtFixedRate():如果第一次执行时间被delay了,随后的执行时间按照上一次开始的时间点进行计算,因此执行时间不会延后,但是存在任务并发的问题。
场景二:任务执行时间超出执行周期间隔(如任务执行完成需要3秒钟,而执行周期是2秒钟)
schedule():下一次执行时间相对于上一次实际执行完成的时间点,因此执行时间会不断延后。比如说,任务真实完成时间是00:03,任务执行周期是2分钟,那么下一次执行时机是上一次任务执行完成的时间,也就是00:03。
scheduledAtFixedRate():下一次执行时间相对于上一次开始的时间点(要加上执行周期),因此执行时间一般不会延后,但存在并发性。
Timer的缺陷:
1.管理并发任务的缺陷:Timer有且仅有一个线程去执行定时任务,如果存在多个任务,且任务时间过长,会导致执行效果与预期不符。
2.当任务抛出异常时的缺陷:对RuntimeException的支持力度不够。如果TimerTask抛出RuntimeException,Timer会停止所有任务的运行。
Timer使用的禁区:
1.对时效性要求较高的多任务并发作业。(因为不支持并发)
2.对复杂的任务的调度。(因为复杂任务容易抛出异常,导致所有任务停止运行)
代码实现:
Timer线程:
package com.wyh;
import java.text.SimpleDateFormat;
import java.util.Timer;
public class MyTimer {
public static void main(String[] args) {
//Timer实例
Timer timer = new Timer();
//MyTimerTask实例
MyTimerTask myTimerTask = new MyTimerTask();
//打印当前时间
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(sf.format(System.currentTimeMillis()));
//timer定时定频率调用myTimerTask的业务逻辑
//即第一次执行是在当前时间三秒之后,之后每隔一秒执行一次
timer.schedule(myTimerTask, 3000L, 1000L);
}
}
TimerTask:
package com.wyh;
import java.text.SimpleDateFormat;
import java.util.TimerTask;
public class MyTimerTask extends TimerTask {
@Override
public void run() {
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("执行任务啦"+sf.format(System.currentTimeMillis()));
}
}
此处调度的任务是打印输出。运行MyTimer进行测试:
简单的Timer定时任务就实现了。