本文转载请联系Java极客技术公众号。一、总结阅读本文大约需要3分钟。本文主要内容如下:SpringBootSchedule实践介绍2.介绍每天晚上23:00生成销售报表,清理脏数据等等。如果你目前正在使用SpringBoot开发项目,那么完成这些任务将会非常轻松!SpringBoot默认已经帮我们完成了相关定时任务组件的配置,我们只需要添加相应的注解@Scheduled即可实现任务调度!三、Schedule实践3.1、pom包配置pom包只需要引入SpringBootStarter包即可!org.springframework.bootspring-boot-starterorg.springframework.bootspring-boot-starter-testtest3.2.启动类启用定时调度在启动类中添加@EnableScheduling启动定时@SpringBootApplication@EnableSchedulingpublicclassScheduleApplication{publicstaticvoidmain(String[]args){SpringApplication.run(ScheduleApplication.class,args);}}3.3.创建定时任务SpringScheduler支持四种形式的任务调度!fixedRate:固定速率执行,比如5秒执行一次fixedDelay:固定延时执行,比如距离上次调用的距离ExecuteinitialDelay2secondsaftersuccess:初始延时任务,比如任务启动后5秒后执行,然后以固定频率或间隔执行cron:使用Cron表达式执行定时任务3.3.1、固定速率执行通过使用fixedRate参数可以按照固定的时间间隔执行任务,如下:MM-ddHH:mm:ss");/***fixedRate:每5秒以固定速率执行。*/@Scheduled(fixedRate=5000)publicvoidrunWithFixedRate(){log.info("FixedRateTask,CurrentThread:{},Thetimeisnow:{}",Thread.currentThread().getName(),dateFormat.format(newDate()));}}运行ScheduleApplication主程序可以看到控制台输出:FixedRateTask,CurrentThread:scheduled-thread-1,Thetimeisnow:2020-12-1511:46:00FixedRateTask,CurrentThread:scheduled-thread-1,Thetimeisnow:2020-12-1511:46:10...3.3.2。固定延迟执行您可以使用fixedDelay参数来设置上一个任务调用完成和下一个任务调用开始之间的延迟时间。示例如下:@ComponentpublicclassSchedulerTask{privatestaticfinalLoggerlog=LoggerFactory.getLogger(SchedulerTask.class);privatestaticfinalSimpleDateFormatdateFormat=newSimpleDateFormat("yyyy-MM-ddHH:mm:ss");/***fixedDelay:固定延时执行。上次调用成功后2秒后执行。*/@Scheduled(fixedDelay=2000)publicvoidrunWithFixedDelay(){log.info("FixedDelayTask,CurrentThread:{},Thetimeisnow:{}",Thread.currentThread().getName(),dateFormat.format(newDate()));}}控制台输出效果:FixedDelayTask,CurrentThread:scheduled-thread-1,Thetimeisnow:2020-12-1511:46:00FixedDelayTask,CurrentThread:scheduled-thread-1,Thetimeisnow:2020-12-1511:46:02。..3.3.3。初始延迟任务initialDelay参数配合fixedRate或fixedDelay可以实现初始延迟任务调度。@ComponentpublicclassSchedulerTask{privatestaticfinalLoggerlog=LoggerFactory.getLogger(SchedulerTask.class);privatestaticfinalSimpleDateFormatdateFormat=newSimpleDateFormat("yyyy-MM-ddHH:mm:ss");/***initialDelay:初始延迟。任务第一次执行会延迟5秒,之后会每隔5秒定时执行一次。*/@Scheduled(initialDelay=5000,fixedRate=5000)publicvoidreportCurrentTimeWithInitialDelay(){log.info("FixedRateTaskwithInitialDelay,CurrentThread:{},Thetimeisnow:{}",Thread.currentThread().getName(),dateFormat.format(newDate()));}}控制台输出效果:FixedRateTaskwithInitialDelay,CurrentThread:scheduled-thread-1,Thetimeisnow:2020-12-1511:46:05FixedRateTaskwithInitialDelay,CurrentThread:scheduled-thread-1,Thetimeisnow:2020-12-1511:46:10...3.3.4。使用Cron表达式SpringScheduler也支持Cron表达式。如果以上简单参数不能满足现有需求,可以使用cron表达式定时执行任务。cron表达式的具体用法可以点此参考:https://cron.qqe2.com/@ComponentpublicclassSchedulerTask{privatestaticfinalLoggerlog=LoggerFactory.getLogger(SchedulerTask.class);privatestaticfinalSimpleDateFormatdateFormat=newSimpleDateFormat("yyyy-MM-ddHH:mm:ss");/***cron:使用Cron表达式。每6秒执行一次*/@Scheduled(cron="*/6****?")publicvoidreportCurrentTimeWithCronExpression(){log.info("CronExpression,CurrentThread:{},Thetimeisnow:{}",Thread.currentThread().getName(),dateFormat.format(newDate()));}}控制台输出效果:CronExpression,CurrentThread:scheduled-thread-1,Thetimeisnow:2020-12-1511:46:06CronExpression,CurrentThread:scheduled-thread-1,Thetimeisnow:2020-12-1511:46:12...3.4。异步执行定时任务每秒执行一个定时任务大约需要3秒。猜猜执行结果是什么?@ComponentpublicclassAsyncScheduledTask{privatestaticfinalLoggerlog=LoggerFactory.getLogger(AsyncScheduledTask.class);privatestaticfinalSimpleDateFormatdateFormat=newSimpleDateFormat("yyyy-MM-ddHH:mm:ss");@Scheduled(fixedRate=2000)publicvoidrunWithFixedDelay(){try{TimeUnit.SECONDS.sleep(3);log.info("FixedDelayTask,CurrentThread:{}:Thetimeisnow{}",Thread.currentThread().getName(),dateFormat.format(newDate()));}catch(InterruptedExceptione){log.error("错误信息",e);}}}控制台输入结果:FixedDelayTask,CurrentThread:scheduling-1:Thetimeisnow2020-12-1517:55:26FixedDelayTask,CurrentThread:scheduling-1:Thetimeisnow2020-12-1517:55:31FixedDelayTask,CurrentThread:scheduling-1:Thetimeisnow2020-12-1517:55:36FixedDelayTask,CurrentThread:scheduling-1:Thetimeisnow2020-12-1517:55:41...很明显任务调度频率变成了每5秒调度一次!为什么是这样?从CurrentThread:scheduling-1的输出可以看出任务执行是同一个线程!默认情况下,@Scheduled任务在Spring中创建,默认线程大小为1在池中执行!更直观的结果是任务是串行执行的!接下来我们把它改成异步线程来执行,看看效果如何?@Component@EnableAsyncpublicclassAsyncScheduledTask{privatestaticfinalLoggerlog=LoggerFactory.getLogger(AsyncScheduledTask.class);privatestaticfinalSimpleDateFormatdateFormat=newSimpleDateFormat("yyyy-MM-ddHH:mm:ss");@Async@Scheduled(fixedDelay=2000)publicvoidrunWithFixedDelay(){try{TimeUnit.SECONDS.sleep(3);log.info("FixedDelayTask,CurrentThread:{}:Thetimeisnow{}",Thread.currentThread().getName(),dateFormat.format(newDate()));}catch(InterruptedExceptione){log.error("errorinformation",e);}}}控制台输出结果:FixedDelayTask,CurrentThread:SimpleAsyncTaskExecutor-1:Thetimeisnow2020-12-1518:55:26FixedDelayTask,CurrentThread:SimpleAsyncTaskExecutor-2:Thetimeisnow2020-12-1518:55:28FixedDelayTask,CurrentThread:SimpleAsyncTaskExecutor-3:Thetimeisnow2020-12-1518:55:30...任务执行频率不受方法中时间影响,并行执行!3.5.虽然自定义任务线程池@Scheduled任务默认是在Spring创建的默认大小为1的线程池中执行的,但是我们也可以通过实现SchedulingConfigurer类来自定义线程池!Examplesofcustomthreadpoolsareasfollows:@ConfigurationpublicclassSchedulerConfigimplementsSchedulingConfigurer{@OverridepublicvoidconfigureTasks(ScheduledTaskRegistrarscheduledTaskRegistrar){ThreadPoolTask??SchedulerthreadPoolTask??Scheduler=newThreadPoolTask??Scheduler();//Thethreadpoolsizeis10threadPoolTask??Scheduler.setPoolSize(10);//SetthethreadnameprefixthreadPoolTask??Scheduler/setThreadNamePrefix)threadpool-offthreadPoolTask??Scheduler/setThreadNamePrefix("等待所有任务完成后再继续销毁其他BeanthreadPoolTask??Scheduler.setWaitForTasksToCompleteOnShutdown(true);//设置线程池中任务的等待时间,如果过了这个时间还没有被销毁,他们将被强行销毁,以确保应用程序是最可以关闭而不是阻塞threadPoolTask??Scheduler.setAwaitTerminationSeconds(60);//这里采用了CallerRunsPolicy策略。当线程池没有处理能力时,策略会直接在execute方法的调用线程中运行被拒绝的任务;如果执行器关闭,则任务会被丢弃CronExpression,CurrentThread:scheduled-thread-1,Thetimeisnow:2020-12-1520:46:00CronExpression,CurrentThread:scheduled-thread-2,Thetimeisnow:2020-12-1520:46:06CronExpression,CurrentThread:scheduled-thread-3,Thetimeisnow:2020-12-1520:46:12CronExpression,CurrentThread:scheduled-thread-4,Thetimeisnow:2020-12-1520:46:18....当前线程名称已更改为自定义调度线程前缀!四、总结本文主要针对Spring调度的应用实践。如果是单体应用,使用SpringBoot内置的@scheduled注解可以解决大部分业务需求,而且非常容易上手!五、参考1、SpringBoot@Schedule用法及原理分析原文链接:https://mp.weixin.qq.com/s/7J1tlZab2oE-6cm6GZiU_w