介绍
定时任务是程序开发中重要且不可缺少的功能,它会自动按照设定好的时间规则,按时完成执行任务,一般周期性更新数据状态,闲时缓存数据,执行计划任务。
本次主要介绍spring scheduled
种类
- 定时任务调度的,一般有3种。
- Timer:java自带定时任务类,单线程执行,适合轻度
- scheduled:spring 官方定时任务调度,配置简单,支持多线程,通过注解设置,支持cron时间格式。
- quartz:功能强大的定时任务调度框架,支持分布式,可动态实现任务调度加载。
cron时间规则
- Cron表达式由6或7个空格分隔的时间字段组成:秒 分钟 小时 日期 月份 星期 年(可选)
字段 允许值 允许的特殊字符
秒 0-59 , - * /
分 0-59 , - * /
小时 0-23 , - * /
日期 1-31 , - * ? / L W C
月份 1-12 , - * /
星期 1-7 , - * ? / L C #
年 1970-2099 , - * /
使用
简单任务
- 通过@EnableScheduling开启定时任务调度。
package com.cn.web.common;
@Component //添加注入
@EnableScheduling //开启定时任务
public class ServiceScheduleTask {
private static final Logger log = LoggerFactory.getLogger(ServiceScheduleTask.class);
@Scheduled(cron = "0/10 * * * * ?") //10秒执行一次
public void getHostService() {
log.info("执行定时任务")
}
}
动态时间
- mysql数据库创建时间规则表,创建crontTest数据库和cron表,3个字段id值、任务名和cron规则。
DROP DATABASE IF EXISTS `cronTest`;
CREATE DATABASE `cronTest`;
USE `cronTest`;
DROP TABLE IF EXISTS `cron`;
CREATE TABLE `cron` (
`cron_id` varchar(30) NOT NULL PRIMARY KEY,
`cron_name` varchar(30) NOT NULL,
`cron` varchar(30) NOT NULL
);
INSERT INTO `cron` VALUES ('1', '0/5 * * * * ?');
- java代码
package com.cn.web.common;
@Component
@EnableScheduling // 开启定时任务
public class DynamicScheduleTask implements SchedulingConfigurer {
private static final Logger log = LoggerFactory.getLogger(DynamicScheduleTask.class);
//定义mybatis接口
@Mapper
public interface CronMapper {
@Select("select cron from cron ")
public Cron getCron();
}
@Autowired //注入mapper
@SuppressWarnings("all")
CronMapper cronMapper;
/**
* 执行定时任务.
*/
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.addTriggerTask(
//1.添加任务内容(Runnable)
() -> log.info("执行动态定时任务: " + LocalDateTime.now().toLocalTime()),
//2.设置执行周期(Trigger)
triggerContext -> {
//2.1 从数据库获取执行周期
Cron cron = cronMapper.getCron();
//2.2 合法性校验.
if (StringUtils.isEmpty(cron.getCronName())) {
if(cron.getCronName().equals("task1")){
//任务一,时间周期为cron.getCront()
}else if(cron.getCronName().equals("task2")){
//任务二,时间周期为cron.getCront()
}
}
//2.3 返回执行周期(Date)
return new CronTrigger(cron).nextExecutionTime(triggerContext);
}
);
}
}
- 如果想实现复杂任务调度,可在通过反射实现多任务功能配置和调度。
开启多线程
- 多线程开启增加注解@EnableAsync开启多线程
package com.cn.web.common;
@Component
@EnableScheduling // 1.开启定时任务
@EnableAsync // 2.开启多线程
public class MultithreadScheduleTask {
private static final Logger log = LoggerFactory.getLogger(MultithreadScheduleTask.class);
@Async
@Scheduled(fixedDelay = 1000) //间隔1秒
public void first() throws InterruptedException {
log.info("第一个定时任务开始时间 : {} 线程名: {}" , LocalDateTime.now().toLocalTime() ,Thread.currentThread().getName());
Thread.sleep(1000 * 10);
}
@Async
@Scheduled(fixedDelay = 2000)
public void second() {
log.info("第二个定时任务开始时间 :{} 线程名:{} " ,LocalDateTime.now().toLocalTime() ,Thread.currentThread().getName());
}
}
总结
- spring boot简单任务建议使用spring自带scheduled,复杂或大量任务建议使用quartz。