我有几个用 @Scheduled(fixedDelay=10000)
注释的方法。
在应用程序上下文中,我有这个注释驱动的设置:
<task:annotation-driven />
问题是,有时某些方法的执行会延迟几秒钟甚至几分钟。
我假设即使一个方法需要一段时间才能完成执行,其他方法仍然会执行。所以我不明白延迟。
有没有办法减少甚至消除延迟?
为了完整起见,下面的代码显示了使用 java config 配置调度程序的最简单方法:
@Configuration
@EnableScheduling
public class SpringConfiguration {
@Bean(destroyMethod = "shutdown")
public Executor taskScheduler() {
return Executors.newScheduledThreadPool(5);
}
...
当需要更多控制时,@Configuration
类可以实现 SchedulingConfigurer
。
documentation about scheduling 说:
如果不提供 pool-size 属性,默认线程池将只有一个线程。
因此,如果您有许多计划任务,您应该按照文档中的说明配置调度程序,以拥有一个具有更多线程的池,以确保一个长任务不会延迟所有其他任务。
pool-size
参数的 task:scheduler
。这是否适用于没有池相关参数的 @Scheduled
注释?
2019 年更新(2022 年仍然有效)
您还可以在应用程序属性文件中设置一个属性来增加池大小:
spring.task.scheduling.pool.size=10
似乎自 Spring Boot 2.1.0 以来就存在。
用 @Scheduled
注释的方法意味着在不同的线程上单独运行。
如果您没有在配置中提供 TaskScheduler
,Spring 将使用
Executors.newSingleThreadScheduledExecutor();
它返回在单个线程上运行的 ScheduledExecutorService
。因此,如果您有多个 @Scheduled
方法,尽管它们是调度的,但它们每个都需要等待线程完成执行上一个任务。随着队列的填满速度快于清空速度,您可能会不断增加越来越大的延迟。
确保使用适当数量的线程配置调度环境。
@Scheduled
(和 @EnableScheduling
)通过注册 ScheduledAnnotationBeanPostProcessor
来处理。此后处理器使用 ScheduledTaskRegistrar
which defaults to that single-threaded ScheduledExecutorService
。
您可以使用:
@Bean()
public ThreadPoolTaskScheduler taskScheduler(){
ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
taskScheduler.setPoolSize(2);
return taskScheduler;
}
taskScheduler
实例之前调用 taskScheduler.initialize();
是一种很好的做法
@EnableScheduling 注释提供了关键信息以及如何解决它:
默认情况下,将搜索关联的调度程序定义:要么是上下文中唯一的 TaskScheduler bean,要么是名为“taskScheduler”的 TaskScheduler bean;还将对 ScheduledExecutorService bean 执行相同的查找。如果两者都不可解析,则将在注册器中创建并使用本地单线程默认调度程序。当需要更多控制时,@Configuration 类可以实现 SchedulingConfigurer。这允许访问底层的 ScheduledTaskRegistrar 实例。例如,以下示例演示了如何自定义用于执行计划任务的 Executor:
@Configuration
@EnableScheduling
public class AppConfig implements SchedulingConfigurer {
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setScheduler(taskExecutor());
}
@Bean(destroyMethod="shutdown")
public Executor taskExecutor() {
return Executors.newScheduledThreadPool(100);
}
}
(重点补充)
使用 XML 文件添加以下行..
<task:scheduler id="taskScheduler" pool-size="15" />
<task:scheduled-tasks scheduler="taskScheduler" >
....
</task:scheduled-tasks>
默认spring使用单线程调度任务。您可以将 @Configuration 用于类实现 SchedulingConfigurer 。参考:https://crmepham.github.io/spring-boot-multi-thread-scheduling/
我们需要传递我们自己的线程池调度器,否则它将使用默认的单线程执行器。已添加以下代码以修复-
@Bean
public Executor scheduledTaskThreadPool() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10);
executor.setMaxPoolSize(10);
executor.setThreadNamePrefix("name-");
executor.initialize();
return executor;
}
Executor
接口没有shutdown()
方法,我想最好使用ExecutorService
作为返回类型以使 bean 定义正确。或者 Spring 会在运行时发现实际的 bean 类型吗?<task:scheduler id="taskScheduler" pool-size="5"/>