解决定时任务@Scheduled没有准时执行的原因及分析

  目录

  定时任务@Scheduled没有准时执行的原因

  项目中用到了定时任务往前端推送数据,间隔2秒 @Scheduled(cron = "0/2 * * * * ? "),测试发现,每次任务执行并不是2秒,而是1-5秒之间。

  执行时间:::::Wed Nov 30 16:20:19 CST 2022

  执行时间:::::Wed Nov 30 16:20:20 CST 2022

  执行时间:::::Wed Nov 30 16:20:24 CST 2022

  执行时间:::::Wed Nov 30 16:20:29 CST 2022

  原因

  了解发现,如果程序中没有指定线程池的配置,也就是Spring的Scheduled的默认线程池配置,其线程池的线程数默认为1,也就是说默认情况下,Spring用来处理定时任务的线程只有一个。

  如果有定时的处理时间占用时间比较长,那么就会导致下一个定时任务,即使到达了配置的定时时间,也不会立即执行,而是等到前面一个任务处理完成了,才会进行处理。

  而项目中还有数个定时任务。

  解决法案

  是初始一个定时任务执行线程池

  @Configuration

  public class ScheduleConfig implements SchedulingConfigurer {

  @Override

  public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {

  Method[] methods = BatchProperties.Job.class.getMethods();

  int defaultPoolSize = 10;

  int corePoolSize = 0;

  if (methods != null && methods.length > 0) {

  for (Method method : methods) {

  Scheduled annotation = method.getAnnotation(Scheduled.class);

  if (annotation != null) {

  corePoolSize++;

  }

  }

  if (defaultPoolSize > corePoolSize)

  corePoolSize = defaultPoolSize;

  }

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

  }

  }

  再次测试,跟设置的间隔时间2秒一致。

  执行时间:::::Wed Nov 30 16:48:32 CST 2022

  执行时间:::::Wed Nov 30 16:48:34 CST 2022

  执行时间:::::Wed Nov 30 16:48:36 CST 2022

  执行时间:::::Wed Nov 30 16:48:38 CST 2022

  定时任务@Scheduled入门

  一个最简单的例子

  启动类添加注解

  @EnableScheduling // 开启定时任务

  编写单线程demo

  cron 表达式

  /**

  * cron 表达式

  * 每2秒执行一次

  * @throws InterruptedException

  */

  @Scheduled(cron = "0/2 * * * * *")

  public void test() throws InterruptedException {

  // 经过测试,使用cron表达式,定时任务第二次会等待第一次执行完毕再开始!

  Thread.sleep(5000L);

  log.info("定时任务测试cron:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));

  }

  fixedDelay

  /**

  * fixedDelay:

  * 第一次执行完毕才会执行第二次,时间间隔变为了7秒

  * @throws InterruptedException

  */

  @Scheduled(fixedDelay = 2000L)

  public void test2() throws InterruptedException {

  Thread.sleep(5000L);

  log.info("定时任务测试fixedDelay:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));

  }

  fixedRate

  /**

  * fixedRate:

  * 每隔2秒就会执行, 但是因为单线程,所以在5秒后会输出,间隔就是5秒

  * @throws InterruptedException

  */

  @Scheduled(fixedRate = 2000L)

  public void test3() throws InterruptedException {

  Thread.sleep(5000L);

  log.info("定时任务测试fixedRate:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));

  }

  如果是一起执行这三个定时任务,那么会一个一个的来, 因为只有一个线程.

  多线程

  /**

  *

  * @author GMaya

  */

  @Configuration

  @EnableAsync

  public class ScheduleConfig {

  @Bean

  public TaskScheduler taskScheduler() {

  ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();

  taskScheduler.setPoolSize(50); // 设置线程池大小

  return taskScheduler;

  }

  }

  如果只是加这一个配置类, 确实是使用了多线程, 每个定时任务都互相不影响.

  但是一个线程第一次阻塞了,第二次就不行了,所以在定时任务上再加

  就是说你这次失败了, 不要影响我下次的运行

  总结

  以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

  您可能感兴趣的文章: