ChatGPT解决这个技术问题 Extra ChatGPT

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

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

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

<task:annotation-driven />

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

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

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

请用“SchedulingConfigurer”将答案标记为正确答案。

G
G. Demecki

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

@Configuration
@EnableScheduling
public class SpringConfiguration {

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

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


由于 Executor 接口没有 shutdown() 方法,我想最好使用 ExecutorService 作为返回类型以使 bean 定义正确。或者 Spring 会在运行时发现实际的 bean 类型吗?
XML 配置 - <task:scheduler id="taskScheduler" pool-size="5"/>
有关 SchedulingConfigurer 的示例,请参见 here
不能与 Spring autoconfig 一起使用:无法注册在类路径资源 [org/springframework/boot/autoconfigure/task/TaskSchedulingAutoConfiguration.class] 中定义的 bean 'taskScheduler'。已在类路径资源中定义了具有该名称的 bean ...
为 Spring Boot >= 2 (在我的例子中是 v2.2.10.RELEASE) stackoverflow.com/a/67567777/6555159 建议一个新的答案
m
mwalter

documentation about scheduling 说:

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

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


仅供参考:仅提供通用文档的链接并说您已“配置它”并无济于事……提供示例会更有帮助。我投票给了g。 Demecki 在下面的答案,而不是你的答案,正是因为这个原因......只是取得成功的提示
引用的文档是指具有 pool-size 参数的 task:scheduler。这是否适用于没有池相关参数的 @Scheduled 注释?
@DavidSoroko 我相信是的。
L
L.Butz

2019 年更新(2022 年仍然有效)

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

spring.task.scheduling.pool.size=10

似乎自 Spring Boot 2.1.0 以来就存在。


如果 spring boot 版本 >= 2.0,这是唯一的方法。重写 taskScheduler() 没用
@jean 据我所知,2.4.3 并非如此。我可以注入这篇文章中提到的我自己的调度程序
S
Sotirios Delimanolis

@Scheduled 注释的方法意味着在不同的线程上单独运行。

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

Executors.newSingleThreadScheduledExecutor();

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

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


链接到 Spring 文档?
@DavidSoroko 这在 Javadoc 中并不是很明显。在源代码中更容易看到它。 @Scheduled(和 @EnableScheduling)通过注册 ScheduledAnnotationBeanPostProcessor 来处理。此后处理器使用 ScheduledTaskRegistrar which defaults to that single-threaded ScheduledExecutorService
我认为您太客气了-根本不在文档中。至于源代码 - 它可以从发布到发布。
s
sj8515465

您可以使用:

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

我认为在返回 taskScheduler 实例之前调用 taskScheduler.initialize(); 是一种很好的做法
使用 Spring Boot v2.2.10.RELEASE 对我不起作用:成功地遵循了@NeeruKSingh 的另一个答案:stackoverflow.com/a/67567777/6555159
j
jgreen

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

(重点补充)


A
Ashok Parmar

使用 XML 文件添加以下行..

<task:scheduler id="taskScheduler" pool-size="15" />
<task:scheduled-tasks scheduler="taskScheduler" >
....
</task:scheduled-tasks>

z
zhaoyou

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


s
shubham sachan

我们需要传递我们自己的线程池调度器,否则它将使用默认的单线程执行器。已添加以下代码以修复-

@Bean
public Executor scheduledTaskThreadPool() {
    ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
    executor.setCorePoolSize(10);
    executor.setMaxPoolSize(10);
    executor.setThreadNamePrefix("name-");
    executor.initialize();
    return executor;
}

关注公众号,不定期副业成功案例分享
关注公众号

不定期副业成功案例分享

领先一步获取最新的外包任务吗?

立即订阅