springboot定时任务机制
定时任务
简单定时任务
springboot使用简单定时任务,非常简单。
三步:
1、@Configuration
标记本类为配置类
2、@EnableScheduling
表示开启springboot的定时任务模块
3、@Scheduled(cron = "0/5 * * * * ?")
通过cron表达式控制执行时间
//1.主要用于标记配置类
@Configuration
// 2.开启定时任务
@EnableScheduling
@Slf4j
public class Schedule {
//3.添加定时任务
@Scheduled(cron = "0/5 * * * * ?")
//或直接指定时间间隔,例如:5秒
//@Scheduled(fixedRate=5000)
private void configureTasks() throws InterruptedException {
log.info("基于注解(@Scheduled)的简单定时器demo: " + LocalDateTime.now());
TimeUnit.SECONDS.sleep(6);
}
@Scheduled(cron = "* * * * * ?")
private void configureTasks1() {
log.error("基于注解(@Scheduled): " + LocalDateTime.now());
}
}
缺点
1、无法修改Scheduled里面cron的值,一旦在代码里写死,启动后就无法修改。
2、如果没有做其他配置,则在spring环境中默认只会有一个子线程来执行所有的定时任务。
可能会出现上一个定时任务的执行时间过长,影响下一个定时任务的执行。
在上述代码中,两个定时任务都是 scheduling-1这个线程来执行的。
动态多线程定时任务
采用这种方式配置定时任务的好处主要有以下几点:
1、多线程执行定时任务,所以定时任务之间不会相互影响
2、可以动态修改cron,(在前一次任务执行完成后才生效)
主要代码
实现SchedulingConfigurer接口
在接口方法configureTasks中,只有一个入参ScheduledTaskRegistrar scheduledTaskRegistrar,我们写的配置静态定时任务,作为cronTasks存储,动态定时任务作为TriggerTask存储。
抽象类
@Configuration
@EnableScheduling
public abstract class ConfigurerScheduling implements SchedulingConfigurer {
/**
* @brief 定时任务名称
*/
private String schedulerName;
/**
* @brief 定时任务周期表达式
*/
private String cron;
@Override
public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
scheduledTaskRegistrar.setScheduler(taskScheduler());
scheduledTaskRegistrar.addTriggerTask(
//执行定时任务
() -> {
processTask();
},
//设置触发器
triggerContext -> {
// 动态获取cron
cron = getCron();
CronTrigger trigger = new CronTrigger(cron);
return trigger.nextExecutionTime(triggerContext);
}
);
}
/**
* 设置TaskScheduler用于注册计划任务
*
* @return
*/
@Bean
public Executor taskScheduler() {
//设置线程名称
ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("thread-%d").build();
//创建线程池
return Executors.newScheduledThreadPool(5, namedThreadFactory);
}
/**
* @brief 任务的处理函数
* 本函数需要由派生类根据业务逻辑来实现
*/
protected abstract void processTask();
/**
* @return String
* @brief 获取定时任务周期表达式
* 本函数由派生类实现,从配置文件,数据库等方式获取参数值
*/
protected abstract String getCron();
}
实现类
@Configuration
@Slf4j
public class TaskDemo1 extends ConfigurerScheduling {
@Value(value = "${task.taskName1.switch}")
private Boolean isSwitch;
@Value(value = "${task.taskName1.cron}")
private String cron;
@Override
protected void processTask() {
if (isSwitch) {
log.info("基于接口SchedulingConfigurer的动态定时任务:"
+ LocalDateTime.now() + ",线程名称:" + Thread.currentThread().getName()
+ " 线程id:" + Thread.currentThread().getId());
}
}
@Override
protected String getCron() {
return cron;
}
}