Does spring @Scheduled annotated methods runs on different threads?
Asked Answered
C

9

112

I have several methods annotated with @Scheduled(fixedDelay=10000).

In the application context, I have this annotation-driven setup:

<task:annotation-driven />

The problem is, sometimes some of the method executions get delayed by seconds and even minutes.

I'm assuming that even if a method takes a while to finish executing, the other methods would still execute. So I don't understand the delay.

Is there a way to maybe lessen or even remove the delay?

Cureall answered 24/2, 2014 at 16:34 Comment(1)
please mark the answer with "SchedulingConfigurer " as a correct one.Colorcast
R
84

Spring 4.x

Code below shows the simplest possible way to configure scheduler with java config:

@Configuration
@EnableScheduling
public class SpringConfiguration {

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

When more control is desired, a @Configuration class may implement SchedulingConfigurer.

Spring Boot

In Spring Boot there is a simple property to configure the thread pool size:

spring.task.scheduling.pool.size=5
Radiocarbon answered 12/2, 2015 at 13:20 Comment(5)
Since the Executor interface does not have shutdown() method, I guess it's better to use ExecutorService as a return type to make the bean definition correct. Or will Spring discover the actual bean type in runtime?Notarial
XML config - <task:scheduler id="taskScheduler" pool-size="5"/>Grip
See here for an example of a SchedulingConfigurerNeu
Does not work together with Spring autoconfig: The bean 'taskScheduler', defined in class path resource [org/springframework/boot/autoconfigure/task/ TaskSchedulingAutoConfiguration.class], could not be registered. A bean with that name has already been defined in class path resource ...Collettecolletti
Suggesting a new answer for this for Spring Boot >= 2 (in my case v2.2.10.RELEASE) https://mcmap.net/q/193818/-does-spring-scheduled-annotated-methods-runs-on-different-threadsSerpentine
D
73

The documentation about scheduling says:

If you do not provide a pool-size attribute, the default thread pool will only have a single thread.

So if you have many scheduled tasks, you should configure the scheduler, as explained in the documentation, to have a pool with more threads, to make sure one long task doesn't delay all the other ones.

Divertissement answered 24/2, 2014 at 17:5 Comment(3)
Just as an fyi: It doesn't help to provide just a link to the general docs and say that you have 'configure it'... Providing an example is infinitely more helpful. I voted for g. Demecki's answer below and not yours for this very reason... Just tips to get aheadYoakum
The quoted documentation refers to task:scheduler which has a pool-size parameter. Does this apply to the @Scheduled annotation which has no pool related parameters?Odette
@DavidSoroko I believe so.Cureall
U
69

If you're using Spring Boot:

There is also a property you can set in your application properties file that increases the pool size:

spring.task.scheduling.pool.size=10

Seems to be there since Spring Boot 2.1.0.

Urtication answered 24/10, 2019 at 15:59 Comment(3)
This is the only way to do that if spring boot version >= 2.0. Override taskScheduler() is uselessEnuresis
@Enuresis As far as I can tell, this is not the case for 2.4.3. I am able to inject my own Scheduler mentioned in this postPompea
Thank you.. is there a way to give prefix to thread?Instillation
I
50

A method annotated with @Scheduled is meant to be run separately, on a different thread at a moment in time.

If you haven't provided a TaskScheduler in your configuration, Spring will use

Executors.newSingleThreadScheduledExecutor();

which returns an ScheduledExecutorService that runs on a single thread. As such, if you have multiple @Scheduled methods, although they are scheduled, they each need to wait for the thread to complete executing the previous task. You might keep getting bigger and bigger delays as the the queue fills up faster than it empties out.

Make sure you configure your scheduling environment with an appropriate amount of threads.

Isologous answered 24/2, 2014 at 17:4 Comment(3)
Link to Spring documentation?Odette
@DavidSoroko This isn't immediately obvious in Javadoc. It's easier to see it in source code. @Scheduled (and @EnableScheduling) is handled by registering a ScheduledAnnotationBeanPostProcessor. This post processor uses a ScheduledTaskRegistrar which defaults to that single-threaded ScheduledExecutorService.Isologous
I think you are too kind - it is not in the documentation at all. As to source code - it can change from release to release.Odette
G
15

The @EnableScheduling annotation provides the key information and how to resolve it:

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

(emphasis added)

Goodall answered 14/8, 2019 at 19:18 Comment(2)
Making taskExecutor() a bean function is pointless, since it's not going to be injected anywhere (therefore no need to keep a singleton bean in memory), but rather called directly from configureTasks(). Thus, shutdown will never be triggered, as Executor wont be a managed bean.Beaman
@YvesCalaci The code is from their docs, not mine.Goodall
A
11

you can use:

@Bean()
public  ThreadPoolTaskScheduler  taskScheduler(){
    ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
    taskScheduler.setPoolSize(2);
    return  taskScheduler;
}
Anima answered 7/1, 2016 at 2:54 Comment(2)
I think its good practice to call taskScheduler.initialize(); before returning your instance of taskSchedulerAlcides
Did not work for me with Spring Boot v2.2.10.RELEASE: Followed another answer from @NeeruKSingh successfully: https://mcmap.net/q/193818/-does-spring-scheduled-annotated-methods-runs-on-different-threadsSerpentine
P
0

Using XML file add below lines..

<task:scheduler id="taskScheduler" pool-size="15" />
<task:scheduled-tasks scheduler="taskScheduler" >
....
</task:scheduled-tasks>
Pappose answered 23/7, 2020 at 13:29 Comment(0)
M
-2

default spring using a single thread for schedule task. you can using @Configuration for class implements SchedulingConfigurer . referce: https://crmepham.github.io/spring-boot-multi-thread-scheduling/

Mangum answered 25/7, 2019 at 7:10 Comment(0)
D
-2

We need to pass our own thread pool scheduler, otherwise it will use default single threaded executor. Have added below code to fix-

@Bean
public Executor scheduledTaskThreadPool() {
    ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
    executor.setCorePoolSize(10);
    executor.setMaxPoolSize(10);
    executor.setThreadNamePrefix("name-");
    executor.initialize();
    return executor;
}
Dendrite answered 28/4, 2022 at 11:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.