SpringBoot中使⽤@scheduled定时执⾏任务需要注意的坑要注意什么坑
不绕弯⼦了,直接说这个坑是啥:
SpringBoot使⽤@scheduled定时执⾏任务的时候是在⼀个单线程中,如果有多个任务,其中⼀个任务执⾏时间过长,则有可能会导致其他后续任务被阻塞直到该任务执⾏完成。也就是会造成⼀些任务⽆法定时执⾏的错觉
可以通过如下代码进⾏测试:
@Scheduled(cron = "0/1 * * * * ? ")
public void deleteFile() throws InterruptedException {
log.info("111delete success, time:" + new Date().toString());
Thread.sleep(1000 * 5);//模拟长时间执⾏,⽐如IO操作,http请求
}
@Scheduled(cron = "0/1 * * * * ? ")
public void syncFile() {
log.info("222sync success, time:" + new Date().toString());
}
/**输出如下:
[pool-1-thread-1] : 111delete success, time:Mon Nov 26 20:42:13 CST 2018
[pool-1-thread-1] : 222sync success, time:Mon Nov 26 20:42:18 CST 2018
[pool-1-thread-1] : 111delete success, time:Mon Nov 26 20:42:19 CST 2018
[pool-1-thread-1] : 222sync success, time:Mon Nov 26 20:42:24 CST 2018
[pool-1-thread-1] : 222sync success, time:Mon Nov 26 20:42:25 CST 2018
[pool-1-thread-1] : 111delete success, time:Mon Nov 26 20:42:25 CST 2018
上⾯的⽇志中可以明显的看到syncFile被阻塞了,直达deleteFile执⾏完它才执⾏了
springboot是啥
⽽且从⽇志信息中也可以看出@Scheduled是使⽤了⼀个线程池中的⼀个单线程来执⾏所有任务的。
**/
/**如果把Thread.sleep(1000*5)注释了,输出如下:
[pool-1-thread-1]: 111delete success, time:Mon Nov 26 20:48:04 CST 2018
[pool-1-thread-1]: 222sync success, time:Mon Nov 26 20:48:04 CST 2018
[pool-1-thread-1]: 222sync success, time:Mon Nov 26 20:48:05 CST 2018
[pool-1-thread-1]: 111delete success, time:Mon Nov 26 20:48:05 CST 2018
[pool-1-thread-1]: 111delete success, time:Mon Nov 26 20:48:06 CST 2018
[pool-1-thread-1]: 222sync success, time:Mon Nov 26 20:48:06 CST 2018
这下正常了
**/
解决办法
1.将@Scheduled注释的⽅法内部改成异步执⾏
如下:
//当然了,构建⼀个合理的线程池也是⼀个关键,否则提交的任务也会在⾃⼰构建的线程池中阻塞
ExecutorService service = wFixedThreadPool(5);
@Scheduled(cron = "0/1 * * * * ? ")
public void deleteFile() {
log.info("111delete success, time:" + new Date().toString());
try {
Thread.sleep(1000 * 5);//改成异步执⾏后,就算你再耗时也不会印象到后续任务的定时调度了
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
@Scheduled(cron = "0/1 * * * * ? ")
public void syncFile() {
log.info("222sync success, time:" + new Date().toString());
});
}
2.把Scheduled配置成成多线程执⾏
@Configuration
public class ScheduleConfig implements SchedulingConfigurer {
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
//当然了,这⾥设置的线程池是corePoolSize也是很关键了,⾃⼰根据业务需求设定
taskRegistrar.wScheduledThreadPool(5));
/**为什么这么说呢?
假设你有4个任务需要每隔1秒执⾏,⽽其中三个都是⽐较耗时的操作可能需要10多秒,⽽你上⾯的语句是这样写的:        taskRegistrar.wScheduledThreadPool(3));
那么仍然可能导致最后⼀个任务被阻塞不能定时执⾏
**/
}
}

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。