spring @Scheduled注释方法是否在不同的线程上运行?


78

我有几种用注释的方法@Scheduled(fixedDelay=10000)

在应用程序上下文中,我具有以下注释驱动的设置:

<task:annotation-driven />

问题是,有时某些方法的执行会延迟几秒钟甚至几分钟。

我假设即使某个方法需要一段时间才能完成执行,其他方法仍将执行。所以我不明白延迟。

有没有办法减少甚至消除延迟?

Answers:


58

为了完整起见,以下代码显示了使用java config配置调度程序的最简单方法:

@Configuration
@EnableScheduling
public class SpringConfiguration {

    @Bean(destroyMethod = "shutdown")
    public Executor taskScheduler() {
        return Executors.newScheduledThreadPool(5);
    }
    ...

当需要更多控制时,@Configuration可以实现一个类SchedulingConfigurer


4
由于Executor接口没有shutdown()方法,所以我认为最好使用ExecutorService返回类型来使Bean定义正确。还是Spring会在运行时发现实际的bean类型?
Vladimir Vagaytsev

1
XML配置-– <task:scheduler id="taskScheduler" pool-size="5"/>
whoami

1
请参阅此处的SchedulingConfigurer示例
crusy

1
不能与Spring autoconfig一起使用:无法注册在类路径资源[org / springframework / boot / autoconfigure / task / TaskSchedulingAutoConfiguration.class]中定义的bean'taskScheduler'。在类路径资源中已经定义了具有该名称的bean……
Phil

52

有关计划文档说:

如果不提供pool-size属性,则默认线程池将只有一个线程。

因此,如果您有许多计划任务,则应按照文档中的说明配置计划程序,以使该池具有更多线程,以确保一个长任务不会延迟其他所有任务。


20
就像一个小伙伴:仅提供指向常规文档的链接并说您已经“配置”它无济于事...提供一个示例无疑会更有帮助。我投票赞成g。Demecki在下面的回答而不是您的回答,这就是这个原因……前进的提示
nterry

引用的文档引用了task:scheduler具有pool-size参数的文档。这是否适用于@Scheduled没有池相关参数的注释?
大卫·索罗科

@DavidSoroko我相信。
星期五

34

带有注解的方法@Scheduled应在某个时间在不同线程上分别运行。

如果您未TaskScheduler在配置中提供,Spring将使用

Executors.newSingleThreadScheduledExecutor();

它返回ScheduledExecutorService在单个线程上运行的。这样,如果您有多个@Scheduled方法,尽管它们是已调度的,但每个方法都需要等待线程完成执行上一个任务。由于队列填满的时间快于清空的时间,因此延迟可能会越来越大。

确保使用适当数量的线程配置调度环境。


链接到Spring文档?
大卫·索罗科

@DavidSoroko在Javadoc中这不是立即显而易见的。在源代码中更容易看到它。@Scheduled(和@EnableScheduling)通过注册来处理ScheduledAnnotationBeanPostProcessor。该后处理器使用ScheduledTaskRegistrar 默认为该单线程的ScheduledExecutorService
Sotirios Delimanolis

4
我认为您太客气了-它根本不在文档中。至于源代码-它可以随版本而变化。
David Soroko

19

更新2019

您还可以在应用程序属性文件中设置一个属性,以增加池的大小:

spring.task.scheduling.pool.size=10

从Spring Boot 2.1.0起似乎就在那里。


2
如果spring boot version> = 2.0,这是唯一的方法。覆盖taskScheduler()无用
吉恩

10

您可以使用:

@Bean()
public  ThreadPoolTaskScheduler  taskScheduler(){
    ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
    taskScheduler.setPoolSize(2);
    return  taskScheduler;
}

2
我认为taskScheduler.initialize();在返回您的实例之前致电给我们的好习惯taskScheduler
-Orby

6

@EnableScheduling注释提供了关键信息,以及如何解决它:

默认情况下,将搜索关联的调度程序定义:上下文中的唯一TaskScheduler Bean,否则为名为“ taskScheduler”的TaskScheduler Bean;对于ScheduledExecutorService bean也将执行相同的查找。如果二者都不可解析,则将在注册器中创建并使用本地单线程默认调度程序

当需要更多控制时,@Configuration类可以实现SchedulingConfigurer。这允许访问基础ScheduledTaskRegistrar实例。例如,以下示例演示了如何自定义用于执行计划任务的执行器:

 @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);
     }
 }

(添加了重点)



-1

使用单个线程执行调度任务的默认spring。您可以将@Configuration用于类实现SchedulingConfigurer。推荐人:https://crmepham.github.io/spring-boot-multi-thread-scheduling/

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.