Search code examples
javaspringspring-bootschedule

Spring @Scheduler parallel running


I have the following 3 classes:

ComponantA

package mytest.spring.test.spring;

import org.apache.log4j.Logger;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component
public class ComponentA {

    Logger log = Logger.getLogger(ComponentB.class);

    @Scheduled(fixedRate=2000)
    public void sayHello() {
        for(int i=1 ; i<=5 ; i++) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            log.info("Hello from ComponentA " + i);
        }
    }
}

ComponentB

package mytest.spring.test.spring;

import org.apache.log4j.Logger;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component
public class ComponentB {

    Logger log = Logger.getLogger(ComponentB.class);

    @Scheduled(fixedRate=2000)
    public void sayHello() {
        for(int i=1 ; i<=3 ; i++) {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            log.info("Hello from ComponentB " + i);
        }
    }
}

MyApplication

package mytest.spring.test.spring;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;

@SpringBootApplication
@EnableScheduling
public class MyApplication {

    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
}

When I execute it, I'm getting the following output:

Hello from ComponentA 1
Hello from ComponentA 2
Hello from ComponentA 3
Hello from ComponentA 4
Hello from ComponentA 5
Hello from ComponentB 1
Hello from ComponentB 2
Hello from ComponentB 3
Hello from ComponentA 1
Hello from ComponentA 2
Hello from ComponentA 3
Hello from ComponentA 4
Hello from ComponentA 5
Hello from ComponentB 1
Hello from ComponentB 2
Hello from ComponentB 3
...

I need the 2 Scheduled methods to run in parallel, which is clearly not the cae according to the output I'm getting. I read that it should be possible to provide the @Schedule annotation with a custom TaskExecutor, with which it should be possible to define how many thread we want ...

Am I right ? I can't find how to provide this information.


Solution

  • The documentation clearly states that:

    By default, will be searching for an associated scheduler definition: either a unique TaskScheduler bean in the context, or a TaskScheduler bean named "taskScheduler" otherwise; the same lookup will also be performed for a ScheduledExecutorService bean. If neither of the two is resolvable, a local single-threaded default scheduler will be created and used within the registrar.

    When more control is desired, a @Configuration class may implement SchedulingConfigurer. This allows access to the underlying ScheduledTaskRegistrar instance. For example, the following example demonstrates how to customize the Executor used to execute scheduled tasks:

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