一、基于注解@Scheduled默认为单线程
直接复制本类即可
/**
* @author yimocha
* @Configuration 主要用于标记配置类,兼备Component的效果。
* @EnableScheduling 开启定时任务
*/
@Configuration
@EnableScheduling
@Slf4j
public class MyTask {
/**
* 添加定时任务
* 基于注解@Scheduled默认为单线程,开启多个任务时,任务的执行时机会受上一个任务执行时间的影响。
*
* @Scheduled(cron = "0/6 * * * * ?")
* 或直接指定时间间隔,例如:6秒
* @Scheduled(fixedRate=6000) 从上一任务开始执行后6s再次调用
*/
@Scheduled(cron = "0/6 * * * * ?")
private void myTaskOne() {
log.info("执行静态定时任务时间: " + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
}
}
Cron表达式:
在线生产Cron表达传送地址
@Scheduled:
除了支持灵活的参数表达式cron之外,还支持简单的延时操作,
例如: fixedDelay ,fixedRate 填写相应的毫秒数即可。
@Scheduled(fixedRate=6000) 周期是以上一个任务开始时间为基准,从上一任务开始执行后6s再次调用
@Scheduled(fixedDelay=5000) 周期是以上一个调用任务的完成时间为基准,在上一个任务完成之后,5s后再次执行
@Scheduled(initialDelay=1000, fixedRate=6000) 固定延迟和固定速率的任务,可以指定一个初始延迟表示该方法在第一被调用执行之前等待的毫秒数
二、数据库动态:基于接口(SchedulingConfigurer)
实际使用中我们往往想从数据库中读取指定时间来动态执行定时任务,这时候基于接口的定时任务就是我们想要的。
task表数据
DROP TABLE IF EXISTS `task`;
CREATE TABLE `task` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`key_code` varchar(64) DEFAULT '' COMMENT '任务键码',
`cron` varchar(64) DEFAULT '' COMMENT 'Cron表达式参数',
`details` varchar(255) DEFAULT '' COMMENT '描述',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4;
INSERT INTO `task` VALUES ('1', 'task_one', '0/10 * * * * ?', '任务一');
数据库持久层 mybatis-plus
java代码
/**
* @Author yimocha
* @Configuration 主要用于标记配置类,兼备Component的效果。
* @EnableScheduling 开启定时任务
**/
@Configuration
@EnableScheduling
public class MyTaskTow implements SchedulingConfigurer {
@Autowired
TaskMapper taskMapper;
/**
* 执行定时任务
* @param scheduledTaskRegistrar
*/
@Override
public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
scheduledTaskRegistrar.addTriggerTask(
//1.添加任务内容(Runnable)
() -> System.out.println("执行动态定时任务: " + LocalDateTime.now().toLocalTime().format(DateTimeFormatter.ofPattern("HH:mm:ss"))),
//2.设置执行周期(Trigger)
triggerContext -> {
// 查询数据库的数据
String cron = taskMapper.selectById(1).getCron();
// 合法性校验.
if (StringUtils.isEmpty(cron)) {
System.out.println("cron为空,执行默认corn,间隔5秒执行");
cron = "0/5 * * * * ?";
}
// 返回执行周期(Date)
return new CronTrigger(cron).nextExecutionTime(triggerContext);
}
);
}
}
如果在数据库修改时格式出现错误,则定时任务会停止,即使重新修改正确;此时只能重新启动项目才能恢复。
三、多线程的定时任务
/**
* @Component 注解用于对那些比较中立的类进行注释;
* 相对与在持久层、业务层和控制层分别采用 @Repository、@Service 和 @Controller 对分层中的类进行注释
* @EnableScheduling 开启定时任务
* @EnableAsync 开启多线程
*/
@Component
@EnableScheduling
@EnableAsync
public class MultithreadScheduleTask {
/**
* @throws InterruptedException
* @Async
* @Scheduled(fixedDelay = 3000) 在上一个任务完成之后,3s后再次执行
*/
@Async
@Scheduled(fixedDelay = 3000)
public void first() throws InterruptedException {
System.out.println("第一个定时任务开始 : " + LocalDateTime.now().toLocalTime() + "\r\n线程 : " + Thread.currentThread().getName());
System.out.println();
Thread.sleep(1000 * 10);
}
/**
* @throws InterruptedException
* @Async
* @Scheduled(fixedDelay = 5000) 在上一个任务完成之后,5s后再次执行
*/
@Async
@Scheduled(fixedDelay = 5000)
public void second() {
System.out.println("第二个定时任务开始 : " + LocalDateTime.now().toLocalTime() + "\r\n线程 : " + Thread.currentThread().getName());
System.out.println();
}
}
开启了多线程,第一个任务的执行时间也不受其本身执行时间的限制,所以需要注意可能会出现重复操作导致数据异常