Does spring @Scheduled annotated methods runs on different threads?

JavaSpringScheduled Tasks

Java Problem Overview


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?

Java Solutions


Solution 1 - Java

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.

Solution 2 - Java

For completeness, 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.

Solution 3 - Java

UPDATE 2019 (still valid in 2022)

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.

Solution 4 - Java

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.

Solution 5 - Java

you can use:

@Bean()
public  ThreadPoolTaskScheduler  taskScheduler(){
    ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
    taskScheduler.setPoolSize(2);
    return  taskScheduler;
}

Solution 6 - Java

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)

Solution 7 - Java

Solution 8 - Java

Using XML file add below lines..

<task:scheduler id="taskScheduler" pool-size="15" />
<task:scheduled-tasks scheduler="taskScheduler" >
....
</task:scheduled-tasks>

Solution 9 - Java

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

Solution 10 - Java

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/

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionfroiView Question on Stackoverflow
Solution 1 - JavaJB NizetView Answer on Stackoverflow
Solution 2 - JavaG. DemeckiView Answer on Stackoverflow
Solution 3 - JavaL.ButzView Answer on Stackoverflow
Solution 4 - JavaSotirios DelimanolisView Answer on Stackoverflow
Solution 5 - Javasj8515465View Answer on Stackoverflow
Solution 6 - JavajgreenView Answer on Stackoverflow
Solution 7 - JavaNeeruKSinghView Answer on Stackoverflow
Solution 8 - JavaAshok ParmarView Answer on Stackoverflow
Solution 9 - Javashubham sachanView Answer on Stackoverflow
Solution 10 - JavazhaoyouView Answer on Stackoverflow