SpringBoot多个排程(定时任务)不同时执行的解决方案

2022-03-13 1156点热度 0人点赞 0条评论

问题描述

SpringBoot下使用定时任务,只需要加几个注释就可以了,详见:https://blog.terrynow.com/2021/07/10/java-spring-springboot-schedule-implement/

不过发现一个问题,就是定时任务比较多,且时间上有冲突的时候,在一个任务执行的时候,如果正好有另一个任务开始,另一个任务可能不会执行,因为SpringBoot默认的定时任务使用的是单列队的执行器(Executors.newSingleThreadScheduledExecutor() ),对同一个排程任务的执行总是同一个列队。如果任务的执行时间超过该任务的下一次执行时间,则会出现任务丢失,跳过该段时间的任务。

解决办法

让定时任务异步执行,给需要执行的Schedule方法加上@Async

@Component
public class ScheduledTask {

    private static final Log log = LogFactory.getLog(ScheduledTask.class);

    //每30秒執行一次
    @Async()
    @Scheduled(fixedRate = 1000 * 3)
    public void testSchedule0() {
        System.out.println("testSchedule0 called: " + Thread.currentThread().getName());
    }

    /**
     * 测试8点21分执行,观察1分钟后和testSchedule2是否会同时执行
     */
    @Scheduled(cron = "0 21 8 ? * *")
    @Async
    public void testSchedule1() {
        for (int i = 0; i < 70; i++) {
            log.error("testSchedule1 called, " + Thread.currentThread().getName());
            try {
                Thread.sleep(1000L);
            } catch (InterruptedException ignored) {
            }
        }
    }

    /**
     * 测试8点22分执行
     */
    @Scheduled(cron = "0 22 8 ? * *")
    @Async
    public void testSchedule2() {
        for (int i = 0; i < 70; i++) {
            log.warn("testSchedule2 called, " + Thread.currentThread().getName());
            try {
                Thread.sleep(1000L);
            } catch (InterruptedException ignored) {
            }
        }
    }

}

在SpringBoot主应用程序上要加上配置才能生效:@EnableAsync

@SpringBootApplication
@EnableScheduling
// 需要加@EnableAsync才能使用@Async
@EnableAsync
public class MyApplication {

    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }

}

办法2

配置SpringBoot让它启动另外的线程来执行定时任务(ThreadPoolTaskScheduler)

@Configuration
@EnableAsync
@EnableScheduling
public class ScheduleConfig implements SchedulingConfigurer {

    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        taskRegistrar.setScheduler(taskScheduler());
    }

    @Bean(name = "taskScheduler")
    public Executor taskScheduler() {
        ThreadPoolTaskScheduler scheduledExecutorService = new ThreadPoolTaskScheduler();
        scheduledExecutorService.setPoolSize(10);
        scheduledExecutorService.setThreadNamePrefix("myTaskScheduler-");
        scheduledExecutorService.setWaitForTasksToCompleteOnShutdown(false);

        return scheduledExecutorService;
    }
}

 

admin

这个人很懒,什么都没留下

文章评论

您需要 登录 之后才可以评论