hublo
hublo

Reputation: 1170

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.

Upvotes: 23

Views: 19845

Answers (2)

michal.jakubeczy
michal.jakubeczy

Reputation: 9459

Configure this property in application.properties:

spring.task.scheduling.pool.size=2

Value means the number of threads which may be used by scheduled tasks. Default pool size is 1 and this setting is available since SpringBoot 2.1.0

The same task will be executed in serialized when the trigger period is shorter than the execution duration. Different tasks will run in parallel with a maximum of threads you set.

Documentation - https://docs.spring.io/spring-boot/docs/current/reference/html/application-properties.html#application-properties.core.spring.task.scheduling.pool.size

Upvotes: 4

miensol
miensol

Reputation: 41608

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

Upvotes: 43

Related Questions