- 任务【1】
@Component public class Test01 { // 每秒执行一次 @Scheduled(cron = "0/1 * * * * ? ") public void test() { // 时分秒 String nowTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss")); // 日志打印 System.out.println(nowTime + " 任务【1】执行 线程:" + Thread.currentThread().getName()); } } • 11
- 任务【2】
@Component public class Test02 { // 每5秒执行一次 @Scheduled(cron = "0/5 * * * * ? ") public void test() { String nowTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss")); System.out.println(nowTime + " 任务【2】执行 线程:" + Thread.currentThread().getName()); try { // 模拟耗时任务,阻塞2s Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } }
- 运行
- 原因
- 由程序运行后的打印结果可以发现两个任务均是使用的同一线程。
- 任务【1】应该是每秒执行一次的,但是执行时间上可以发现,任务【1】的执行时间不是连续的,这就说明有时间点是任务【1】没有执行的,而这些时间点恰好任务【2】正在执行中,单线程的原因线程此时阻塞,从而导致这些时间点任务【1】没有执行。
- 解决添加@Async注解或者使用自定义线程池执行任务在上面的任务【1】和任务【2】的@Scheduled注解上面添加一个注解@Async即可
- 多线程执行定时任务
注意:对@Async进行自定义配置,内部也是通过创建ThreadPoolExecutor线程池来执行。
- 全局配置:实现SchedulingConfigurer接口
@Configuration public class ScheduledConfig implements SchedulingConfigurer { @Override public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) { // 自定义调度器,设置为一个支持定时及周期性的任务执行的线程池,这里初始3个线程 scheduledTaskRegistrar.setScheduler(Executors.newScheduledThreadPool(3)); } }
统一配置后不需要添加@Async注解或者创建线程池实现异步执行定时任务
定时任务执行的线程达到多线程执行,任务【1】执行时间连续,没有出现未执行的情况,且线程也是反复使用的三个。
自定义调度器的时候,只能设置
TaskScheduler
和ScheduledExecutorService
类型,除此之外的类型都会报错