上两章节,我们简单的讲解了关于异步调用和异步请求相关知识点。这一章节,我们来讲讲开发过程也是经常会碰见的定时任务。比如每天定时清理无效数据、定时发送短信、定时发送邮件、支付系统中的定时对账等等,往往都会定义一些定时器,进行此业务的开发。所以,本章节介绍下在SpringBoot中定时任务如何使用及一点分布式定时服务的思考总结。
一点知识
在JAVA开发领域,目前可以通过以下几种方式进行定时任务:
Timer:jdk中自带的一个定时调度类,可以简单的实现按某一频度进行任务执行。提供的功能比较单一,无法实现复杂的调度任务。
ScheduledExecutorService:也是jdk自带的一个基于线程池设计的定时任务类。其每个调度任务都会分配到线程池中的一个线程执行,所以其任务是并发执行的,互不影响。
Spring Task:Spring提供的一个任务调度工具,支持注解和配置文件形式,支持Cron表达式,使用简单但功能强大。
Quartz:一款功能强大的任务调度器,可以实现较为复杂的调度功能,如每月一号执行、每天凌晨执行、每周五执行等等,还支持分布式调度,就是配置稍显复杂。
题外话:对于Quartz,早前用过1.6版本的,更新到2.x及以上版本后基本没怎么接触了,原来还有倒腾过结合Kettle做了一些动态的定时抽取数据啥的还编写过一个Cron表达式编辑器,现在基本忘记了。。等有机会,再次深入学习后再来单独分享一些关于的Quartz心得吧。
基于JDK方式实现简单定时刚刚有介绍过,基于JDK方式一共有两种:Timer和ScheduledExecutorService。接下来,就简单讲解下这两种方式。
TimerTimer是jdk提供的java.util.Timer类。
简单示例:
@GetMapping("/timer") public String doTimer() { Timer timer = new Timer(); timer.schedule(new TimerTask() { @Override public void run() { log.info("Timer定时任务启动:" + new Date()); } }, 1000,1000);//延迟1秒启动,每1秒执行一次 return "timer";启动后,访问即可看见控制台周期性输出信息了:
2018-08-18 21:30:35.171 INFO 13352 --- [ Timer-0] c.l.l.s.c.controller.TaskController : Timer定时任务启动:Sat Aug 18 21:30:35 CST 2018 2018-08-18 21:30:36.173 INFO 13352 --- [ Timer-0] c.l.l.s.c.controller.TaskController : Timer定时任务启动:Sat Aug 18 21:30:36 CST 2018 2018-08-18 21:30:37.173 INFO 13352 --- [ Timer-0] c.l.l.s.c.controller.TaskController : Timer定时任务启动:Sat Aug 18 21:30:37 CST 2018 2018-08-18 21:30:38.173 INFO 13352 --- [ Timer-0] c.l.l.s.c.controller.TaskController : Timer定时任务启动:Sat Aug 18 21:30:38 CST 2018 2018-08-18 21:30:39.174 INFO 13352 --- [ Timer-0] c.l.l.s.c.controller.TaskController : Timer定时任务启动:Sat Aug 18 21:30:39 CST 2018 ......相关API简单说明:
1、在特定时间执行任务,只执行一次
public void schedule(TimerTask task,Date time)2、在特定时间之后执行任务,只执行一次
public void schedule(TimerTask task,long delay)3、指定第一次执行的时间,然后按照间隔时间,重复执行
public void schedule(TimerTask task,Date firstTime,long period)4、在特定延迟之后第一次执行,然后按照间隔时间,重复执行
public void schedule(TimerTask task,long delay,long period)5、第一次执行之后,特定频率执行,与3同
public void scheduleAtFixedRate(TimerTask task,Date firstTime,long period)6、在delay毫秒之后第一次执行,后按照特定频率执行
public void scheduleAtFixedRate(TimerTask task,long delay,long period)参数:
delay: 延迟执行的毫秒数,即在delay毫秒之后第一次执行
period:重复执行的时间间隔
取消任务使用:timer.cancel()方法即可注销任务。
此类相对用的较少了,简单了解下。
ScheduledExecutorServiceScheduledExecutorService可以说是Timer的替代类,因为Timer不支持多线程,任务是串行的,而且也不捕获异常,假设某个任务异常了,整个Timer就无法运行了。
简单示例:
@GetMapping("/executor") public String ScheduledExecutorService() { // ScheduledExecutorService service = Executors.newScheduledThreadPool(10); service.scheduleAtFixedRate(new Runnable() { @Override public void run() { log.info("ScheduledExecutorService定时任务执行:" + new Date()); } }, 1, 1, TimeUnit.SECONDS);//首次延迟1秒,之后每1秒执行一次 log.info("ScheduledExecutorService定时任务启动:" + new Date()); return "ScheduledExecutorService!"; }启动后,可看见控制台按设定的频率输出:
2018-08-18 22:03:24.840 INFO 6752 --- [nio-8080-exec-1] c.l.l.s.c.controller.TaskController : ScheduledExecutorService定时任务启动:Sat Aug 18 22:03:24 CST 2018 2018-08-18 22:03:25.841 INFO 6752 --- [pool-1-thread-1] c.l.l.s.c.controller.TaskController : ScheduledExecutorService定时任务执行:Sat Aug 18 22:03:25 CST 2018 2018-08-18 22:03:26.842 INFO 6752 --- [pool-1-thread-1] c.l.l.s.c.controller.TaskController : ScheduledExecutorService定时任务执行:Sat Aug 18 22:03:26 CST 2018 2018-08-18 22:03:27.841 INFO 6752 --- [pool-1-thread-2] c.l.l.s.c.controller.TaskController : ScheduledExecutorService定时任务执行:Sat Aug 18 22:03:27 CST 2018 2018-08-18 22:03:28.840 INFO 6752 --- [pool-1-thread-1] c.l.l.s.c.controller.TaskController : ScheduledExecutorService定时任务执行:Sat Aug 18 22:03:28 CST 2018 2018-08-18 22:03:29.840 INFO 6752 --- [pool-1-thread-3] c.l.l.s.c.controller.TaskController : ScheduledExecutorService定时任务执行:Sat Aug 18 22:03:29 CST 2018可同时设置多个任务,只需再次设置scheduleAtFixedRate即可。
常用方法说明:
ScheduleAtFixedRate:
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,long initialDelay,long period,TimeUnit unit);参数说明:
command:执行线程
initialDelay:初始化延时
period:两次开始执行最小间隔时间
unit:计时单位
ScheduleWithFixedDelay:
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,long initialDelay,long delay,TimeUnit unit);参数说明:
command:执行线程
initialDelay:初始化延时
delay:前一次执行结束到下一次执行开始的间隔时间(间隔执行延迟时间)
unit:计时单位
其他的方法大家可自行谷歌下。
基于SpingTask实现定时任务使用SpringTask在SpringBoot是很简单的,使用@Scheduled注解即可轻松搞定。