Spring Boot中的并发计划方法

3

我有一个使用Spring框架的应用程序,其中有两个被@Comonent注解的类,在每个类中,我都有一个被@Scheduled注解的方法,这意味着我想要按照固定的间隔运行这些方法,就像这样:

这是第一个组件,它有一个readFirstComponent()方法,该方法从某个地方读取一些内容,并且需要一段时间来执行, @Component public class FirstComp {

@Scheduled(fixedRate = 20000 )
public void readFirstComponent() {
    // body
}

//其他方法 }

第二个组件几乎与第一个组件做的一样,

@Component

公共类 SecondComp {
@Scheduled(fixedRate = 20000 )
public void readSecondComponent() {
    // body
}

//其他方法 }

我有一个运行类来启动应用程序

@SpringBootApplication
@EnableScheduling
@ImportResource("classpath:spring/Spring-AutoScan.xml")
public class Application {
public static void main(final String args[]) {
    SpringApplication.run(Application.class);    
}

}

当我启动应用程序时,首先启动FirtComp并执行readFirstComponent(),大约14秒后结束,然后启动SecondComp中的readSecondComponent(),以此类推。 我的问题是我想同时启动这两种方法,请帮我解决这个问题。
2个回答

5
默认情况下,只有一个线程来运行调度任务。
您可以在这里阅读相关信息,并了解如何配置调度程序以获得更多的线程池。

27.4.1 启用调度注释

要启用对@Scheduled和@Async注释的支持,请将@EnableScheduling和@EnableAsync添加到其中一个@Configuration类中:

@Configuration
@EnableAsync
@EnableScheduling
public class AppConfig {
}

您可以自由选择与应用程序相关的注释。例如,如果您只需要支持@Scheduled,则可以省略@EnableAsync。如果您需要更细粒度的控制,还可以实现SchedulingConfigurer和/或AsyncConfigurer接口。有关完整详细信息,请参阅javadoc。
如果您喜欢XML配置,请使用元素。
<task:annotation-driven executor="myExecutor" scheduler="myScheduler"/>
<task:executor id="myExecutor" pool-size="5"/>
<task:scheduler id="myScheduler" pool-size="10"/>

注意上述XML中提供了执行器引用,用于处理与@Async注释对应的任务,提供了调度程序引用,用于管理使用@Scheduled注释的方法。

由于您使用注释来配置bean,因此最好实现SchedulingConfigurer。

像这样:

@Configuration
@EnableScheduling
public class SchedulingConfig implements SchedulingConfigurer {

@Override
public void configureTasks(
  ScheduledTaskRegistrar taskRegistrar) {
    taskRegistrar.setScheduler(taskExecutor());
}

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

请将以下与编程相关的内容从英文翻译成中文。只返回翻译后的文本:还请复制链接中最相关的部分,因为链接往往会被删除。 - undefined
好的,非常感谢您提供的信息。我会努力提高我的回答能力。 - undefined

4

虽然这是一个旧的问题,但我自己也在处理它。我无法使用上面提供的解决方法,因为我需要确保每个方法只运行一个实例。而增加默认的计划线程池大小意味着如果方法执行时间超过计划间隔,我可能会遇到麻烦。

因此,我创建了两个包含单个线程的线程池,然后注释每个方法以使用相关的线程池(即单线程)。

创建线程池:

@SpringBootApplication
@EnableScheduling
@EnableAsync(proxyTargetClass=true)
public class MainApplication {

    public static void main(String[] args) {
        SpringApplication application = new SpringApplication(MainApplication.class);   
        application.run(args);
    }       

    @Bean("schedulePool1")
    public Executor jobPool() {
        ThreadPoolTaskExecutor exec = new ThreadPoolTaskExecutor();
        exec.setCorePoolSize(1);
        exec.setMaxPoolSize(1);
        exec.setQueueCapacity(10);
        exec.setThreadNamePrefix("first-");
        exec.initialize();
        return exec;
    }       

    @Bean("schedulePool2")
    public Executor jobPool2() {
        ThreadPoolTaskExecutor exec = new ThreadPoolTaskExecutor();
        exec.setCorePoolSize(1);
        exec.setMaxPoolSize(1);
        exec.setQueueCapacity(10);
        exec.setThreadNamePrefix("second-");
        exec.initialize();
        return exec;
    }
}

然后你可以在两个计划方法中添加@Async注释。
@Async("schedulePool1")
@Scheduled(fixedRate = 20000 )
public void readFirstComponent() {
    // body
}

并且

@Async("schedulePool2")
@Scheduled(fixedRate = 20000 )
public void readSecondComponent() {
    // body
}

然后在您的日志中,您应该看到带有正确[线程]的内容:

2020-02-21 20:47:01 [first-1] INFO  sodved.JobSchedule - running readFirstComponent
...
2020-02-21 20:47:01 [second-1] INFO  sodved.JobService - running readSecondComponent

正是我在寻找的东西。谢谢你的分享! - undefined
如果您不使用Async注释,而只是将线程池大小设置为组件的数量,会怎么样?例如:两个组件 => spring.task.scheduling.pool.size=2。您还需要使用fixDelay而不是fixRate,以便在上一个完成后立即开始下一个间隔周期,因此如果某个方法所需时间超过了间隔时间,也不会有问题。 - undefined
@SoheilPourbafrani 那么同样的方法可以同时运行两次。 - undefined
@flup 永远不会!假设有两个线程和两种不同的方法。除了阻塞方法调用(Synch)之外,具有相同的fixDelay可以保证这一点。 - undefined
啊,是的。我忽略了fixedDelay部分。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接