春季启动时的并发计划方法

时间:2018-06-13 14:04:54

标签: java spring scheduled-tasks

我有一个spring应用程序,它有两个用@Component注释的类,在每个类中,我有一个用@Scheduled注释的方法,这意味着我想以固定的间隔运行这些方法,如下所示:

这是First Component,它有一个readFirstComponent()方法,这个方法从某个地方读取内容,需要一段时间才能执行,     @零件 公共课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正在启动并且在将近14秒结束后执行readFirstComponent(),然后来自SecondComp的readSecondComponent()启动,依此类推, 我的问题是我想同时启动这两种方法,请帮我解决这个问题

2 个答案:

答案 0 :(得分:2)

默认情况下,只有一个线程可以运行调度任务。

您可以阅读它here并了解如何配置调度程序以获得包含更多线程的池。

  

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,因此implement the 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);
}
}

答案 1 :(得分:0)

一个老问题,但我本人正在处理。我无法使用上面提供的解决方案,因为我需要确保每种方法一次只运行一个实例。并且增加默认的调度线程池大小意味着如果方法花费的时间超过间隔时间,我可能会陷入麻烦。

因此,我改为创建了2个线程池,每个线程池一个,然后注释每种方法以使用相关的线程池(即单线程)。

创建线程池:

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

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

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
相关问题