一、阅读收获 1。了解常用的单体应用定时任务框架 2。掌握定时任务在单体中如何使用二、本章源码下载 本章源码下载已分享github三、TimerTimerTask这是jdk自带的java。util。Timer类,这个类允许你调度一个java。util。TimerTask任务。使用这种方式可以让你的程序按照某一个频度执行,但不能在指定时间运行,一般用的较少。Description:1。TimerTimerTask:(jdk自带)这是java自带的java。util。Timer类,这个类允许你调度一个java。util。TimerTask任务。使用这种方式可以让你的程序按照某一个频度执行,但不能在指定时间运行。一般用的较少。Author:jianweildate:2021121413:36publicclassTimerTest{publicstaticvoidmain(String〔〕args){TimerTasktimerTasknewTimerTask(){Overridepublicvoidrun(){System。out。println(taskrun:newDate());}};TimerTasktimerTask2newTimerTask(){Overridepublicvoidrun(){System。out。println(task2run:newDate());多线程并行处理定时任务时,Timer运行多个TimeTask时,只要其中之一没有捕获抛出的异常,其它任务便会自动终止运行,使用ScheduledExecutorService则没有这个问题。inti10;}};idea会提示:使用ScheduledExecutorService代替Timer吧TimertimernewTimer();System。out。println(begin:newDate());安排指定的任务在指定的时间开始进行重复的固定延迟执行。这里是延迟5秒开始执行,之后每3秒执行一次timer。schedule(timerTask,5000,3000);timer。schedule(timerTask2,5000,3000);}}多线程并行处理定时任务时,Timer运行多个TimeTask时,只要其中之一没有捕获抛出的异常,其它任务便会自动终止运行,使用ScheduledExecutorService则没有这个问题。四、ScheduledExecutorServiceScheduledExecutorService也是jdk自带的定时类,可以替代Timerpackagecom。ljw。springboottimer。scheduledExecutorservice;importorg。apache。commons。lang3。concurrent。BasicThreadFactory;importjava。util。Date;importjava。util。concurrent。ScheduledExecutorService;importjava。util。concurrent。ScheduledThreadPoolExecutor;importjava。util。concurrent。TimeUnit;Description:2。ScheduledExecutorService代替Timer(jdk自带)多线程并行处理定时任务时,Timer运行多个TimeTask时,只要其中之一没有捕获抛出的异常,其它任务便会自动终止运行,使用ScheduledExecutorService则没有这个问题。Author:jianweildate:2021121413:42publicclassScheduledExecutorServiceTest{publicstaticvoidmain(String〔〕args)throwsInterruptedException{当所有的非守护线程结束时,程序也就终止了,同时会杀死进程中的所有守护线程。反过来说,只要任何非守护线程还在运行,程序就不会终止。ScheduledExecutorServiceexecutorServicenewScheduledThreadPoolExecutor(1,newBasicThreadFactory。Builder()。namingPattern(exampleschedulepoold)。daemon(false)。build());System。out。println(begin:newDate());参数:1、任务体2、首次执行的延时时间3、任务执行间隔4、间隔时间单位延迟5秒执行,之后每3秒执行一次executorService。scheduleAtFixedRate(newRunnable(){Overridepublicvoidrun(){dosomethingSystem。out。println(begin:newDate());}},5,3,TimeUnit。SECONDS);}}五、SpringTaskspring提供的类,可引入依赖:dependencygroupIdorg。springframework。bootgroupIdspringbootstarterartifactIddependency复制代码开启定时任务:EnableScheduling使用:在相应的任务方法前加上注解Scheduled即可5。1单线程串行执行ScheduledScheduled注解默认使同一个线程中串行执行,如果只有一个定时任务,这样做肯定没问题,当定时任务增多,如果一个任务卡死,会导致其他任务也无法执行。业务测试:ComponentEnableSchedulingpublicclassSpringTaskTest{Scheduled(cron05)publicvoidrun()throwsInterruptedException{System。out。println(Thread。currentThread()。getName()使用cron{}(System。currentTimeMillis()1000));}}复制代码5。2多线程并发运行Scheduled配置定时器的程池(推荐)解决单线程串行执行任务的问题,需要配置定时器的程池,推荐这种方法配置并注入一个TaskScheduler类bean即可配置定时器的线程池类如下:packagecom。ljw。springboottimer。springtask;importorg。springframework。context。annotation。Bean;importorg。springframework。context。annotation。Configuration;importorg。springframework。scheduling。TaskScheduler;importorg。springframework。scheduling。concurrent。ThreadPoolTaskScheduler;Description:解决单线程串行执行方式2:Scheduled配置定时器的线程池Author:jianweildate:2021121414:44ConfigurationpublicclassTaskSchedulerConfig{初始化了一个线程池大小为5的TaskScheduler,避免了所有任务都用一个线程来执行returnBeanpublicTaskSchedulertaskScheduler(){ThreadPoolTaskSchedulertaskSchedulernewThreadPoolTaskScheduler();taskScheduler。setPoolSize(5);taskScheduler。setThreadNamePrefix(TaskSchedulerConfigljw);returntaskScheduler;}}业务测试ComponentEnableSchedulingpublicclassSpringTaskTest{Scheduled(cron05)publicvoidrun()throwsInterruptedException{System。out。println(Thread。currentThread()。getName()使用cron{}(System。currentTimeMillis()1000));}Scheduled(fixedRate5000)publicvoidrun1()throwsInterruptedException{System。out。println(Thread。currentThread()。getName()使用fixedRate{}(System。currentTimeMillis()1000));}}5。3多线程并发执行ScheduledAsync配置异步线程池解决单线程串行执行任务的问题,也可以结合异步注解Async实现,但这种方法并不推荐,需要两个注解,代码编写的工作量大还可以解决fixedRate在遇到某些执行任务时间超过配置的时间隔,下次任务时间到了还要等待上次任务执行完成的情况,这是3。2不能解决的。配置异步线程池类如下:packagecom。ljw。springboottimer。springtask;importorg。springframework。context。annotation。Configuration;importorg。springframework。scheduling。annotation。AsyncConfigurer;importorg。springframework。scheduling。annotation。EnableAsync;importorg。springframework。scheduling。concurrent。ThreadPoolTaskExecutor;importjava。util。concurrent。Executor;importjava。util。concurrent。ThreadPoolExecutor;Description:解决单线程串行执行方式1:ScheduledAsync配置异步线程池Author:jianweildate:2021121414:35ConfigurationEnableAsyncpublicclassAsyncConfigimplementsAsyncConfigurer{定义Async默认的线程池ThreadPoolTaskExecutor不是完全被IOC容器管理的bean,可以在方法上加上Bean注解交给容器管理,这样可以将taskExecutor。initialize()方法调用去掉,容器会自动调用returnOverridepublicExecutorgetAsyncExecutor(){intprocessorsRuntime。getRuntime()。availableProcessors();常用的执行器ThreadPoolTaskExecutortaskExecutornewThreadPoolTaskExecutor();核心线程数taskExecutor。setCorePoolSize(10);taskExecutor。setMaxPoolSize(50);线程队列最大线程数,默认:50taskExecutor。setQueueCapacity(100);线程名称前缀taskExecutor。setThreadNamePrefix(AsyncConfigljw);taskExecutor。setRejectedExecutionHandler(newThreadPoolExecutor。CallerRunsPolicy());执行初始化(重要)taskExecutor。initialize();returntaskExecutor;}}业务测试需要加上Async注解ComponentEnableSchedulingpublicclassSpringTaskTest{Scheduled(cron05)Asyncpublicvoidrun()throwsInterruptedException{System。out。println(Thread。currentThread()。getName()使用cron{}(System。currentTimeMillis()1000));}Scheduled(fixedRate5000)Asyncpublicvoidrun1()throwsInterruptedException{System。out。println(Thread。currentThread()。getName()使用fixedRate{}(System。currentTimeMillis()1000));}}如果同时配置了3。2配置定时器的程池和3。3配置异步线程池,并且注解使用了ScheduledAsync,则定时任务使用的线程池为:配置异步线程池5。4Scheduled参数解析cron:通过cron表达式来配置任务执行时间(默认是fixedDelay)initialDelay:定义该任务延迟多少时间才开始第一次执行fixedRate:定义一个按一定频率执行的定时任务。fixedRate每次任务结束后会从任务编排表中找下一次该执行的任务,判断是否到时机执行,fixedRate的任务某次执行时间再长也不会造成两次任务实例同时执行,也要等到上次任务完成,判断是否到时机执行,到就立即执行,与线程池无关,除非用了Async注解,使方法异步,即是使用5。3步骤的配置。(5。2是配置线程池,达不到效果)fixedDelay:定义一个按一定频率执行的定时任务。fixedDelay总是在前一次任务完成后,延时固定时间长度然后再执行下一次任务六、Quartz 在开发Quartz相关应用时,只要定义了Job(任务),JobDetail(任务描述),Trigger(触发器)和Scheduler(调度器),即可实现一个定时调度能力。 如果SpringBoot版本是2。0。0以后的,则在springbootstarter中已经包含了quart的依赖,则可以直接引入依赖:dependencygroupIdorg。springframework。bootgroupIdspringbootstarterquartzartifactIddependency6。1。创建任务类方式1:实现Job类的execute方法即可实现一个任务(推荐)任务1如下:packagecom。ljw。springboottimer。quartz。do1;importorg。quartz。Job;importorg。quartz。JobExecutionContext;importorg。quartz。JobExecutionException;importjava。util。Date;Description:我的定时任务方法1Author:jianweildate:2021121416:06publicclassMyTaskService1implementsJob{Overridepublicvoidexecute(JobExecutionContextjobExecutionContext)throwsJobExecutionException{System。out。println(Thread。currentThread()。getName()JobnewDate());}}方式2:继承QuartzJobBean类重写方法即可实现一个任务任务2如下:packagecom。ljw。springboottimer。quartz。do1;importorg。quartz。JobExecutionContext;importorg。quartz。JobExecutionException;importorg。springframework。scheduling。quartz。QuartzJobBean;importjava。util。Date;Description:我的定时任务方法2Author:jianweildate:2021121416:06publicclassMyTaskService2extendsQuartzJobBean{OverrideprotectedvoidexecuteInternal(JobExecutionContextcontext)throwsJobExecutionException{System。out。println(Thread。currentThread()。getName()QuartzJobBeannewDate());}}6。2。配置任务描述和触发器配置类要分别要为每个任务声明两个bean1。JobDetail(任务描述)2。Trigger(触发器)配置调度器信息使用SimpleScheduleBuilder或者CronScheduleBuilderpackagecom。ljw。springboottimer。quartz。do1;importorg。quartz。;importorg。springframework。context。annotation。Bean;importorg。springframework。context。annotation。Configuration;importjava。util。Date;Description:每个任务都要两步配置1。配置任务描述JobDetail2。配置触发器TriggerAuthor:jianweildate:2021121416:08ConfigurationpublicclassQuartzConfig{创建任务1的JobDetail1returnBeanpublicJobDetailteatQuartzDetail1(){returnJobBuilder。newJob(MyTaskService1。class)job的描述。withDescription(thisisajob1)job的name和group。withIdentity(myTrigger1,myTriggerGroup1)。storeDurably()。build();}创建任务2的JobDetail2returnBeanpublicJobDetailteatQuartzDetail2(){returnJobBuilder。newJob(MyTaskService2。class)job的描述。withDescription(thisisajob2)job的name和group。withIdentity(myTrigger2,myTriggerGroup2)。storeDurably()。build();}创建任务1的Trigger1returnBeanpublicTriggertestQuartzTrigger1(){使用SimpleScheduleBuilder或者CronScheduleBuilderSimpleScheduleBuilderscheduleBuilderSimpleScheduleBuilder。simpleSchedule()设置时间周期单位秒。withIntervalInSeconds(10)。repeatForever();两秒执行一次,Quartz表达式,支持各种牛逼表达式CronScheduleBuildercronScheduleBuilderCronScheduleBuilder。cronSchedule(03?);任务运行的时间,SimpleSchedle类型触发器有效,3秒后启动任务longtimeSystem。currentTimeMillis()31000L;DatestatTimenewDate(time);returnTriggerBuilder。newTrigger()。withDescription()。forJob(teatQuartzDetail1())。withIdentity(myTrigger1,myTriggerGroup1)默认当前时间启动。startAt(statTime)。withSchedule(cronScheduleBuilder)。withSchedule(scheduleBuilder)。build();}创建任务2的Trigger2returnBeanpublicTriggertestQuartzTrigger2(){SimpleScheduleBuilderscheduleBuilderSimpleScheduleBuilder。simpleSchedule()设置时间周期单位秒。withIntervalInSeconds(10)。repeatForever();returnTriggerBuilder。newTrigger()。forJob(teatQuartzDetail2())。withIdentity(myTrigger2,myTriggerGroup2)。withSchedule(scheduleBuilder)。build();}}