You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository has been archived by the owner on Sep 6, 2023. It is now read-only.
2017-12-21 23:12:20.007 INFO 13208 --- [pool-1-thread-1] c.e.demo.scheduled.ScheduledTaskDemo : First scheduled task is starting... ...
2017-12-21 23:12:35.013 INFO 13208 --- [pool-1-thread-1] c.e.demo.scheduled.ScheduledTaskDemo : First scheduled task is ending... ...
2017-12-21 23:12:35.016 INFO 13208 --- [pool-1-thread-1] c.e.demo.scheduled.SecondScheduledTaskDemo : Second scheduled task is starting... ...
2017-12-21 23:12:35.016 INFO 13208 --- [pool-1-thread-1] c.e.demo.scheduled.SecondScheduledTaskDemo : Second scheduled task is ending... ...
2017-12-21 23:12:40.000 INFO 13208 --- [pool-1-thread-1] c.e.demo.scheduled.ScheduledTaskDemo : First scheduled task is starting... ...
2017-12-21 23:12:55.001 INFO 13208 --- [pool-1-thread-1] c.e.demo.scheduled.ScheduledTaskDemo : First scheduled task is ending... ...
2017-12-21 23:12:55.002 INFO 13208 --- [pool-1-thread-1] c.e.demo.scheduled.SecondScheduledTaskDemo : Second scheduled task is starting... ...
2017-12-21 23:12:55.002 INFO 13208 --- [pool-1-thread-1] c.e.demo.scheduled.SecondScheduledTaskDemo : Second scheduled task is ending... ...
/** * Set the {@link org.springframework.scheduling.TaskScheduler} that will invoke * the scheduled methods, or a {@link java.util.concurrent.ScheduledExecutorService} * to be wrapped as a TaskScheduler. * <p>If not specified, default scheduler resolution will apply: searching for a * unique {@link TaskScheduler} bean in the context, or for a {@link TaskScheduler} * bean named "taskScheduler" otherwise; the same lookup will also be performed for * a {@link ScheduledExecutorService} bean. If neither of the two is resolvable, * a local single-threaded default scheduler will be created within the registrar. * @see #DEFAULT_TASK_SCHEDULER_BEAN_NAME */publicvoidsetScheduler(Objectscheduler) {
this.scheduler = scheduler;
}
重点来了, 注意这句话:
If neither of the two is resolvable, a local single-threaded default scheduler will be created within the registrar.
@ConfigurationpublicclassScheduledTaskConfigurationimplementsSchedulingConfigurer {
/** * Callback allowing a {@link TaskScheduler * TaskScheduler} and specific {@link Task Task} * instances to be registered against the given the {@link ScheduledTaskRegistrar} * * @param taskRegistrar the registrar to be configured. */@OverridepublicvoidconfigureTasks(ScheduledTaskRegistrartaskRegistrar) {
finalThreadPoolTaskSchedulertaskScheduler = newThreadPoolTaskScheduler();
taskScheduler.setPoolSize(2);
taskScheduler.initialize();
taskRegistrar.setTaskScheduler(taskScheduler);
}
}
2017-12-21 23:28:30.001 INFO 7972 --- [TaskScheduler-1] c.e.demo.scheduled.ScheduledTaskDemo : Second scheduled task is starting... ...
2017-12-21 23:28:30.001 INFO 7972 --- [TaskScheduler-2] c.e.demo.scheduled.ScheduledTaskDemo : First scheduled task is starting... ...
2017-12-21 23:28:30.002 INFO 7972 --- [TaskScheduler-1] c.e.demo.scheduled.ScheduledTaskDemo : Second scheduled task is ending... ...
2017-12-21 23:28:40.001 INFO 7972 --- [TaskScheduler-1] c.e.demo.scheduled.ScheduledTaskDemo : Second scheduled task is starting... ...
2017-12-21 23:28:40.001 INFO 7972 --- [TaskScheduler-1] c.e.demo.scheduled.ScheduledTaskDemo : Second scheduled task is ending... ...
2017-12-21 23:28:45.002 INFO 7972 --- [TaskScheduler-2] c.e.demo.scheduled.ScheduledTaskDemo : First scheduled task is ending... ...
可以看到, 当线程池里有两个线程的时候, 这两个定时任务各自按照预定的时间进行触发, 互不影响了.
The text was updated successfully, but these errors were encountered:
在SpringBoot中可以通过
@Scheduled
注解来定义一个定时任务, 下面这段代码定义了一个每隔十秒钟执行一次的定时任务:此时启动SpringBoot应用, 可以在控制台看到这个定时任务每隔10秒钟打印一条log
但是, 一切还没结束.
在上面的相关代码中, 我们使用cron表达式来指定定时任务的执行时间点, 即从0秒开始, 每隔10秒钟执行一次, 现在我们再加一个定时任务:
现在再启动SpringBoot应用, 再看log:
注意log中定时任务执行的时间点, 第二个定时任务原本应该每隔10秒钟执行一次, 但是从23:12:20到23:13:55, 本该执行4次, 确只执行了2次.
难道是cron表达式不对?
No.
为了找到原因, 我们从
@Scheduled
注解的源码开始找:划重点, 每一个有
@Scheduled
注解的方法都会被注册为一个ScheduledAnnotationBeanPostProcessor
, 再接着往下看ScheduledAnnotationBeanPostProcessor
:重点来了, 注意这句话:
这句话意味着, 如果我们不主动配置我们需要的
TaskScheduler
, SpringBoot会默认使用一个单线程的scheduler来处理我们用@Scheduled
注解实现的定时任务, 到此我们刚才的问题就可以理解了:23:12:20, 第一个定时任务在线程pool-1-thread-1开始执行, 由于我们没有配置scheduler, 目前这个线程池pool-1里只有一个线程, 在打印了starting日志之后, 这个线程开始sleep;第二个定时任务也准备执行, 但是线程池已经没有多余线程了, 只能等待.
23:12:30, 第一个定时任务还在sleep, 第二个定时任务还在等待.
23:12:35, 第一个定时任务sleep结束, 打印ending日志并结束, 此时线程池空闲, 第二个定时任务从等待状态直接开始执行, 执行结束之后, 线程池空闲.
23:12:40, 线程池空闲, 第一个定时任务执行, 打印starting日志, 开始sleep.
... ...
搞清楚这个流程之后, 解决这个问题就很简单了.
根据刚才注释的描述, 我们只需要提供一个满足我们需要的
TaskScheduler
并注册到context中就可以了.上面的代码提供了一个线程池大小为2的taskScheduler, 现在再启动下SpringBoot看看效果.
可以看到, 当线程池里有两个线程的时候, 这两个定时任务各自按照预定的时间进行触发, 互不影响了.
The text was updated successfully, but these errors were encountered: