SpringBoot中使用@scheduled定时执行任务的坑

网友投稿 674 2022-10-03

SpringBoot中使用@scheduled定时执行任务的坑

SpringBoot中使用@scheduled定时执行任务的坑

目录解决办法1.将@Scheduled注释的方法内部改成异步执行2.把Scheduled配置成成多线程执行

要注意什么坑

不绕弯子了,直接说这个坑是啥:

SpringBoot使用@scheduled定时执行任务的时候是在一个单线程中,如果有多个任务,其中一个任务执行时间过长,则有可能会导致其他后续任务被阻塞直到该任务执行完成。也就是会造成一些任务无法定时执行的错觉

可以通过如下代码进行测试:

@Scheduled(cron = "0/1 * * * * ? ")

public void deleteFile() throws InterruptedException {

log.info("111delehttp://te 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

上面的日志中可以明显的看到syiqYLOjsbncFile被阻塞了,直达deleteFile执行完它才执行了

而且从日志信息中也可以看出@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-threahttp://d-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 = Executors.newFixedThreadPool(5);

@Scheduled(cron = "0/1 * * * * ? ")

public void deleteFile() {

service.execute(() -> {

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() {

service.execute(()->{

log.info("222sync success, time:" + new Date().toString());

});

}

2.把Scheduled配置成成多线程执行

@Configuration

public class ScheduleConfig implements SchedulingConfigurer {

@Override

public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {

//当然了,这里设置的线程池是corePoolSize也是很关键了,自己根据业务需求设定

taskRegistrar.setScheduler(Executors.newScheduledThreadPool(5));

/**为什么这么说呢?

假设你有4个任务需要每隔1秒执行,而其中三个都是比较耗时的操作可能需要10多秒,而你上面的语句是这样写的:

taskRegistrar.setScheduler(Executors.newScheduledThreadPool(3));

那么仍然可能导致最后一个任务被阻塞不能定时执行

**/

}

}

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:HDU 3966 Aragorn's Story (树链剖分)
下一篇:HDU 6118 度度熊的交易计划 (最小费用最大流)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~