什么是Cron表达式
cron表达式是由7个子表达式组成的字符串,每个子表达式代表一个时间域(秒、分钟、小时、日、月、周、年),用空格分隔。每个时间域都可以指定一个或多个值,范围或通配符,用于精确地定义任务的执行时刻。
例如,一个常见的cron表达式 "0 0 12 * * ?" 表示每天12点整执行任务。
以下是cron表达式各部分的详细说明:
- 秒(0-59)
- 分钟(0-59)
- 小时(0-23)
- 日(1-31)
- 月(1-12)
- 周(1-7,其中1和7代表周日)
- 年(1970-2199,可选)
cron表达式还支持特殊字符,如星号(*)代表任意值,逗号(,)用于列举多个值,连字符(-)用于指定范围,斜线(/)用于指定步长等。
基本使用
启动类添加@EnableScheduling注解
@SpringBootApplication
@EnableScheduling
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
业务类定时任务添加@Scheduled注解
@Component
public class MyScheduleTask {
// 每3秒执行一次
@Scheduled(cron = "*/3 * * * * ?")
public void repeatPrintTime(){
System.out.printf("task1 %s %s%n", Thread.currentThread().getName(), LocalTime.now().toString());
}
}
思考
启动多个定时任务时,定时任务之间会互相影响吗?
定时任务默认是单线程的,当task1未执行完成时,task2会阻塞
解决:实现
SchedulingConfigurer接口,并重写configureTasks方法
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import java.util.concurrent.Executors;
@Configuration
public class ScheduleConfig implements SchedulingConfigurer {
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
// 结合实际情况配置
int corePoolSize = taskRegistrar.getScheduledTasks().size()
+ taskRegistrar.getCronTaskList().size()
+ taskRegistrar.getFixedDelayTaskList().size()
+ taskRegistrar.getFixedRateTaskList().size()
+ 3
;
taskRegistrar.setScheduler(Executors.newScheduledThreadPool(corePoolSize));
System.out.printf("ScheduleConfig corePoolSize: %d %n", corePoolSize);
}
}
同一个定时任务,上一个定时任务执行未结束,下一个定时任务是否会执行?
上一个定时任务未执行完成时,下一个定时任务会阻塞;
但是定时任务的启动时间一直符合@Scheduled设置规则
解决:业务逻辑使用线程池去执行,定时任务只起到调用的作用
@Component
@EnableAsync
public class MyScheduleTask {
// 每3秒执行一次
@Scheduled(cron = "*/3 * * * * ?")
public void repeatPrintTime() throws InterruptedException {
System.out.printf("task1 start %s %s%n", Thread.currentThread().getName(), LocalTime.now().toString());
asyncPrintTime();
System.out.printf("task1 end %s %s%n", Thread.currentThread().getName(), LocalTime.now().toString());
}
// 注意自定义线程池配置
@Async
public void asyncPrintTime() throws InterruptedException {
Thread.sleep(10*1000);
}
}
定时任务增加分布式锁
待补充~~~
定时任务原理
待补充~~~