1.定时任务-Spring Task
通过先前的例子,我们使用jdk自带的定时器实现了定时任务,当然我们也可以采用spring给我们提供的定时任务处理模块Spring Scheduler
.
1.2 例子-helloworld
1.2.1 新建项目
image-20200428111024028.png image-20200428111040941.png注意:没有导入任何依赖
1.2.2 编码
-
撰写任务
package com.spring.task.demo.task; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; @Component public class Task { @Scheduled(cron = "*/10 * * * * ?") public void test1() { System.out.println("====== 任务1 ===="); } }
-
在启动类上加上
image-20200428112519855.png@EnableScheduling
-
启动程序(每隔10s执行一次)
image-20200428112711464.png
1.2.3 helloword解析
image-20200428112853564.png从上图中我们可以看出,方法test1
上面加入了@Scheduled
注解。
-
@Scheduled
这个注解加在方法上,将一个普通的方法声明为一个任务。到时候被调度。
-
cron
是一个表达式。不同的*
代表着不同的涵义。其格式为秒 分 时 日 月 周 年
具体用法如下所示:字段名 允许的值 特殊字符 秒 0 - 59 , - * / 分 0 - 59 , - * / 时 0 - 23 , - * / 日 0 - 31 , - * ? / L W 月 1 - 12 或 JAN - DEC , - * / 周 1 - 7 或 SUN - SAT , - * ? / L # 年(可选) empty 或 1970 - 2099 , - * / -
特殊字符含义如下:
,
指定数个值-
指定一个值的范围*
表示任何可能的值/
指定一个值的增加幅度。 n / m 表示 从 n 开始,每次增加 m?
表示不确定的值L
用在 日 表示一个月的最后一天,用在周表示该月最后的一个星期XW
指定离给定日期最近的工作日(周一到周五)#
表示该月的第几个周X,6#3 表示该月第三个周五 -
练习:
每隔五秒执行一次
*/5 * * * * ?
每隔1分钟执行一次
0 */1 * * * ?
每天2点执行一次
0 0 2 * * * ?
每个月1号1点执行一次
0 0 1 1 * ?
每天 0点 13点执行 1次
0 0 0,13 * * ?
当然你如果不熟悉,或者是一下不能够想起这种语法怎么办。我们可以采用一些工具帮我们生成 cron表示式子
工具地址: https://www.pppet.net/
image-20200428124006443.png
例如每个月 3号 9号的6点和9点执行一次,用工具就可以快速生成:
image-20200428124349247.png-
启动类
一定要在启动类上加上
@EnableScheduling
注解,这个注解就是开启任务调度
1.2.4 其他特性
我们通过cron表达式可以指定任务的运行,当然我们也可以去使用其他的方式去运行
-
上次任务完成后,1毫秒执行,也就是间隔1毫秒执行
image-20200428124540140.png -
第一次立马执行,然后间隔五秒执行
image-20200428125126042.png -
第一次延迟3秒执行,以后每个五秒执行
image-20200428125338305.png
1. 串行任务
通过helloword我们明白了spring task 基本用法,接下来我们分析如果时多个任务,那么时串行的还是并行的。
-
测试代码:
image-20200428125936776.pngpackage com.spring.task.demo.task; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; @Component public class Task { @Scheduled(fixedRate = 1000) public void test1() { System.out.println("====== 任务1 开始 ===="); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("====== 任务1 结束 ===="); } @Scheduled(fixedRate = 1000) public void test2() { System.out.println("====== 任务2 开始 ===="); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("====== 任务2 结束 ===="); } }
从结果发现,当任务1结束以后,才能够执行任务2.这是因为默认采用的时串行任务策略。但在实际开发过程中,如果有多个任务,且任务之间互不相关,那么应该采用并行任务才合理。
1.4 并行任务
要将将默认的串行任务修改成串行任务,那么我们只需要写一个任务调度的配置类即可。
其实原理差不多,让线程池里面的一个线程去执行任务,不同的线程执行不同的任务
-
代码和解释如下:
image-20200428131942508.pngpackage com.spring.task.demo.config; import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.AsyncConfigurer; import org.springframework.scheduling.annotation.SchedulingConfigurer; import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; import org.springframework.scheduling.config.ScheduledTaskRegistrar; import java.util.concurrent.Executor; /** * 并行任务配置类 */ @Configuration public class ScheduleConfig implements SchedulingConfigurer, AsyncConfigurer { /** * 线程池线程数量 */ private int corePoolSize = 5; /** * 创建线程池 */ @Bean public ThreadPoolTaskScheduler taskScheduler() { ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); scheduler.initialize(); scheduler.setPoolSize(corePoolSize); return scheduler; } @Override public Executor getAsyncExecutor() { return taskScheduler(); } @Override public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { return null; } @Override public void configureTasks(ScheduledTaskRegistrar taskRegistrar) { // 设置线程池 taskRegistrar.setTaskScheduler(taskScheduler()); } }
我们可以看见几乎同时开始任务,并且互不影响。
网友评论