billshortz
billshortz

Reputation: 97

How to run the same @Scheduled method in Spring Boot in multiple threads

I currently have a @Scheduled method in my Spring Boot app

   @Async
    @Scheduled(fixedDelay = 2000, initialDelay = 1000)
    public void taskA() throws InterruptedException {
        System.out.println("A - " + Thread.currentThread().getName());
    }

My Spring Application file is as follows: @SpringBootApplication

@EnableAsync
@EnableScheduling
public class SpringScheduleApplication {

    public static void main(String[] args) {

        SpringApplication.run(SpringScheduleApplication.class, args);
    }


}

I also have a config class set up to establish a thread pool to allow for parallel jobs

@Configuration
@EnableScheduling
public class SchedulingConfig implements SchedulingConfigurer {
    public static final int NUM_PROCESSING_WORKERS = 10;
    @Override
    public void configureTasks(
            ScheduledTaskRegistrar taskRegistrar) {
        taskRegistrar.setScheduler(taskExecutor());
    }

    @Bean
    public Executor taskExecutor() {
        return Executors.newScheduledThreadPool(NUM_PROCESSING_WORKERS);
    }
}

When I run the scheduler, I can clearly see the job is picking up in the multiple thread pools.

A - pool-1-thread-7
A - pool-1-thread-3
A - pool-1-thread-9
....

Ok..... so here's my problem

What I WANT to do is create multiple instances of taskA and have that run in N amount of threads.

I know I can create N amount of methods with the @Scheduled annotation performing the same logic, but this is NOT an acceptable solution. This seems very redundant and looks bad, and don't want to copy paste if I add another thread to the pool. I want to be able to say something like:

for(int i = 0; i < SchedulingConfig.NUM_PROCESSING_WORKERS; i++){
  taskA(); // I just want N amount of this tasks existing in parallel.
}

I cannot use anything like Quartz Scheduler because I want to be able to continue to use @Autowired in my project (I can get this behavior to work in Quartz, but setting up @Autowired is a pain and I would like to work with Spring Schedule annotations as much as possible)

Upvotes: 0

Views: 4206

Answers (1)

M. Deinum
M. Deinum

Reputation: 124441

You already wrote the answer yourself. You already have the for loop to use. Put the @Scheduled on the method with the for-loop, which calls a taskA method in an external class, and which has the @Async annotation.


@Autowired
private External external

@Scheduled
public void scheduler() {
  for(int i = 0; i < SchedulingConfig.NUM_PROCESSING_WORKERS; i++){
    external.taskA(); // I just want N amount of this tasks existing in parallel.
  }
}
public class External {


  @Async
  public void taskA() { ... }

}

Another solution is to inject the AsyncTaskExecutor into your class that does the scheduling and call submit to execute the task.

@Autowired
private AsyncTaskExecutor taskExecutor;

@Scheduled
public void scheduler() {
  for(int i = 0; i < SchedulingConfig.NUM_PROCESSING_WORKERS; i++){
    taskExecutor.submit( () -> taskA());  
  }
}

The advantage of this is that it is more explicit and that your taskA method can be in the same class.

Upvotes: 3

Related Questions