0


SpringBoot【注解 01】@Scheduled实现定时任务的串行和并行执行

在SpringBoot中,如果使用

@Scheduled

注解来定义多个定时任务,默认情况下这些任务将会被安排在一个单线程的调度器中执行。这意味着,这些任务将会串行执行,而不是并行执行。当一个任务正在执行时,其他被触发的任务将会等待当前任务完成后再开始执行,这可能导致任务执行上的阻塞,特别是当某个任务执行时间较长时,可能会延迟后续任务的启动时间,影响定时任务的准时性。

@Scheduled

1.问题代码及测试结果

问题代码:

@Scheduled(cron ="*/1 * * * * *")publicvoida()throwsInterruptedException{
        log.info("A Start {}!",System.currentTimeMillis());Thread.sleep(2000);
        log.info("A End {}!",System.currentTimeMillis());}@Scheduled(cron ="*/1 * * * * *")publicvoidb(){
        log.info("B Start {}!",System.currentTimeMillis());
        log.info("B End {}!",System.currentTimeMillis());}

部分测试结果:

15:38:29.001[scheduling-1]INFOc.x.e.m.SchedulerTask-[b,52]-BStart1716968309001!15:38:29.001[scheduling-1]INFOc.x.e.m.SchedulerTask-[b,53]-BEnd1716968309001!15:38:29.001[scheduling-1]INFOc.x.e.m.SchedulerTask-[a,44]-AStart1716968309001!15:38:31.003[scheduling-1]INFOc.x.e.m.SchedulerTask-[a,46]-AEnd1716968311003!15:38:31.003[scheduling-1]INFOc.x.e.m.SchedulerTask-[b,52]-BStart1716968311003!15:38:31.003[scheduling-1]INFOc.x.e.m.SchedulerTask-[b,53]-BEnd1716968311003!15:38:32.002[scheduling-1]INFOc.x.e.m.SchedulerTask-[a,44]-AStart1716968312002!15:38:34.003[scheduling-1]INFOc.x.e.m.SchedulerTask-[a,46]-AEnd1716968314003!15:38:34.003[scheduling-1]INFOc.x.e.m.SchedulerTask-[b,52]-BStart1716968314003!15:38:34.003[scheduling-1]INFOc.x.e.m.SchedulerTask-[b,53]-BEnd1716968314003!

结果分析:

  • A和B是串行的。

2.定时任务实现并行

2.1 使用自定义线程池(添加类)

可以通过配置一个自定义的

TaskScheduler

或者

ThreadPoolTaskScheduler

来为

@Scheduled

任务提供一个线程池,从而允许多个任务并行执行。例如,可以在配置类中定义一个

ThreadPoolTaskScheduler

Bean:

@ConfigurationpublicclassAsyncConfig{@BeanpublicThreadPoolTaskSchedulertaskScheduler(){ThreadPoolTaskScheduler scheduler =newThreadPoolTaskScheduler();// 设置线程池大小
        scheduler.setPoolSize(10); 
        scheduler.setThreadNamePrefix("my-scheduled-task-");return scheduler;}}

并确保你的配置类被扫描到,且在

@EnableScheduling

注解的上下文中。
测试代码:

@Scheduled(cron ="*/1 * * * * *")publicvoida()throwsInterruptedException{
        log.info("A Start {}!",System.currentTimeMillis());Thread.sleep(2000);
        log.info("A End {}!",System.currentTimeMillis());}@Scheduled(cron ="*/1 * * * * *")publicvoidb(){
        log.info("B Start {}!",System.currentTimeMillis());
        log.info("B End {}!",System.currentTimeMillis());}

部分测试结果:

15:16:18.003[my-scheduled-task-2]INFOc.x.e.m.SchedulerTask-[a,44]-AStart1716966978003!15:16:18.003[my-scheduled-task-1]INFOc.x.e.m.SchedulerTask-[b,52]-BStart1716966978003!15:16:18.003[my-scheduled-task-1]INFOc.x.e.m.SchedulerTask-[b,53]-BEnd1716966978003!15:16:19.002[my-scheduled-task-1]INFOc.x.e.m.SchedulerTask-[b,52]-BStart1716966979002!15:16:19.002[my-scheduled-task-1]INFOc.x.e.m.SchedulerTask-[b,53]-BEnd1716966979002!15:16:20.004[my-scheduled-task-2]INFOc.x.e.m.SchedulerTask-[a,46]-AEnd1716966980004!15:16:20.004[my-scheduled-task-3]INFOc.x.e.m.SchedulerTask-[b,52]-BStart1716966980004!15:16:20.004[my-scheduled-task-3]INFOc.x.e.m.SchedulerTask-[b,53]-BEnd1716966980004!15:16:21.003[my-scheduled-task-1]INFOc.x.e.m.SchedulerTask-[a,44]-AStart1716966981003!15:16:21.003[my-scheduled-task-4]INFOc.x.e.m.SchedulerTask-[b,52]-BStart1716966981003!15:16:21.003[my-scheduled-task-4]INFOc.x.e.m.SchedulerTask-[b,53]-BEnd1716966981003!15:16:22.001[my-scheduled-task-2]INFOc.x.e.m.SchedulerTask-[b,52]-BStart1716966982001!15:16:22.001[my-scheduled-task-2]INFOc.x.e.m.SchedulerTask-[b,53]-BEnd1716966982001!15:16:23.004[my-scheduled-task-1]INFOc.x.e.m.SchedulerTask-[a,46]-AEnd1716966983004!15:16:23.004[my-scheduled-task-3]INFOc.x.e.m.SchedulerTask-[b,52]-BStart1716966983004!15:16:23.004[my-scheduled-task-3]INFOc.x.e.m.SchedulerTask-[b,53]-BEnd1716966983004!

结果分析:

  • A和B是并行的;
  • A和A或者B和B是串行的。

2.2 使用异步处理(添加类和注解)

结合

@Async

注解和@EnableAsync可以使得每个@Scheduled任务在独立的线程中异步执行。
首先需要在配置类中启用异步支持,并配置一个线程池,然后在每个定时任务方法上添加@Async注解。

@EnableAsync@ConfigurationpublicclassAsyncConfig{@BeanpublicExecutortaskExecutor(){ThreadPoolTaskExecutor executor =newThreadPoolTaskExecutor();
        executor.setCorePoolSize(10);
        executor.setMaxPoolSize(20);
        executor.setQueueCapacity(200);
        executor.setThreadNamePrefix("Async-");
        executor.initialize();return executor;}}

测试代码:

@Async@Scheduled(cron ="*/1 * * * * *")publicvoida()throwsInterruptedException{
        log.info("A Start {}!",System.currentTimeMillis());Thread.sleep(2000);
        log.info("A End {}!",System.currentTimeMillis());}@Async@Scheduled(cron ="*/1 * * * * *")publicvoidb(){
        log.info("B Start {}!",System.currentTimeMillis());
        log.info("B End {}!",System.currentTimeMillis());}

部分测试结果:

15:26:52.008[Async-2]INFOc.x.e.m.SchedulerTask-[a,44]-AStart1716967612008!15:26:52.008[Async-1]INFOc.x.e.m.SchedulerTask-[b,52]-BStart1716967612008!15:26:52.009[Async-1]INFOc.x.e.m.SchedulerTask-[b,53]-BEnd1716967612009!15:26:53.002[Async-4]INFOc.x.e.m.SchedulerTask-[a,44]-AStart1716967613002!15:26:53.002[Async-3]INFOc.x.e.m.SchedulerTask-[b,52]-BStart1716967613002!15:26:53.002[Async-3]INFOc.x.e.m.SchedulerTask-[b,53]-BEnd1716967613002!15:26:54.001[Async-6]INFOc.x.e.m.SchedulerTask-[a,44]-AStart1716967614001!15:26:54.001[Async-5]INFOc.x.e.m.SchedulerTask-[b,52]-BStart1716967614001!15:26:54.001[Async-5]INFOc.x.e.m.SchedulerTask-[b,53]-BEnd1716967614001!15:26:54.010[Async-2]INFOc.x.e.m.SchedulerTask-[a,46]-AEnd1716967614010!15:26:55.002[Async-8]INFOc.x.e.m.SchedulerTask-[a,44]-AStart1716967615002!15:26:55.002[Async-7]INFOc.x.e.m.SchedulerTask-[b,52]-BStart1716967615002!15:26:55.002[Async-7]INFOc.x.e.m.SchedulerTask-[b,53]-BEnd1716967615002!15:26:55.002[Async-4]INFOc.x.e.m.SchedulerTask-[a,46]-AEnd1716967615002!15:26:56.001[Async-10]INFOc.x.e.m.SchedulerTask-[a,44]-AStart1716967616001!15:26:56.001[Async-9]INFOc.x.e.m.SchedulerTask-[b,52]-BStart1716967616001!15:26:56.001[Async-9]INFOc.x.e.m.SchedulerTask-[b,53]-BEnd1716967616001!15:26:56.002[Async-6]INFOc.x.e.m.SchedulerTask-[a,46]-AEnd1716967616002!15:26:57.001[Async-3]INFOc.x.e.m.SchedulerTask-[a,44]-AStart1716967617001!15:26:57.001[Async-1]INFOc.x.e.m.SchedulerTask-[b,52]-BStart1716967617001!15:26:57.001[Async-1]INFOc.x.e.m.SchedulerTask-[b,53]-BEnd1716967617001!15:26:57.002[Async-8]INFOc.x.e.m.SchedulerTask-[a,46]-AEnd1716967617002!

测试结果分析:

  • A和B是并行的;
  • A和A或者B和B也是并行的。

3.总结

如有错误,请小伙伴儿们不吝赐教。
定时任务有不同的需求,使用串行还是并行要结合业务进行选择。


本文转载自: https://blog.csdn.net/weixin_39168541/article/details/139298574
版权归原作者 シ風箏 所有, 如有侵权,请联系我们删除。

“SpringBoot【注解 01】@Scheduled实现定时任务的串行和并行执行”的评论:

还没有评论