Spring Boot — How to Schedule Tasks | Code Factory
Donate : Link
WordPress Blog : Link
You’ll learn how to schedule tasks in Spring Boot using @Scheduled
annotation. You’ll also learn how to use a custom thread pool for executing all the scheduled tasks.
The @Scheduled
annotation is added to a method along with some information about when to execute it, and Spring Boot takes care of the rest.
Spring Boot internally uses the TaskScheduler
interface for scheduling the annotated methods for execution.
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>spring-boot-scheduler-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring-boot-scheduler-demo</name>
<description>Demo project for Spring Boot</description> <properties>
<java.version>1.8</java.version>
</properties> <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies> <build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build></project>
You can enable scheduling simply by adding the @EnableScheduling
annotation to the main application class or one of the Configuration classes.
Open SpringBootSchedulerDemoApplication.java
and add @EnableScheduling
annotation like so -
package com.example;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;@SpringBootApplication
@EnableScheduling
public class SpringBootSchedulerDemoApplication { public static void main(String[] args) {
SpringApplication.run(SpringBootSchedulerDemoApplication.class, args);
}}
Scheduling a task with Spring Boot is as simple as annotating a method with @Scheduled
annotation, and providing few parameters that will be used to decide the time at which the task will run.
Before adding tasks, Let’s first create the container for all the scheduled tasks. Create a new class called ScheduledTasks
inside com.example.schedule
package with the following contents -
package com.example.schedule;import java.time.format.DateTimeFormatter;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;@Component
public class ScheduledTasks {
private static final Logger logger = LoggerFactory.getLogger(ScheduledTasks.class);
private static final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss"); public void scheduleTaskWithFixedRate() {} public void scheduleTaskWithFixedDelay() {} public void scheduleTaskWithInitialDelay() {} public void scheduleTaskWithCronExpression() {}
}
The class contains four empty methods. We’ll look at the implementation of all the methods one by one.
All the scheduled methods should follow the following two criteria -
- The method should have a void return type.
- The method should not accept any arguments.
1. Scheduling a Task with Fixed Rate
You can schedule a method to be executed at a fixed interval by using fixedRate
parameter in the @Scheduled
annotation. In the following example, The annotated method will be executed every 2 seconds.
@Scheduled(fixedRate = 2000)
public void scheduleTaskWithFixedRate() {
logger.info("Fixed Rate Schedule : " + dateTimeFormatter.format(LocalDateTime.now()));
}
Output :
Fixed Rate Schedule : 14:33:40
Fixed Rate Schedule : 14:33:42
Fixed Rate Schedule : 14:33:44
Fixed Rate Schedule : 14:33:46
...
...
The fixedRate
task is invoked at the specified interval even if the previous invocation of the task is not finished.
2. Scheduling a Task with Fixed Delay
You can execute a task with a fixed delay between the completion of the last invocation and the start of the next, using fixedDelay
parameter.
The fixedDelay
parameter counts the delay after the completion of the last invocation.
Consider the following example -
@Scheduled(fixedDelay = 2000)
public void scheduleTaskWithFixedDelay() {
logger.info("Fixed Delay Schedule : " + dateTimeFormatter.format(LocalDateTime.now()));
try {
TimeUnit.SECONDS.sleep(5);
} catch(InterruptedException e) {
e.printStackTrace();
}
}
Output :
Fixed Delay Schedule : 14:35:58
Fixed Delay Schedule : 14:36:05
Fixed Delay Schedule : 14:36:12
Fixed Delay Schedule : 14:36:19
...
...
Since the task itself takes 5 seconds to complete and we have specified a delay of 2 seconds between the completion of the last invocation and the start of the next, there will be a delay of 7 seconds between each invocation
3. Scheduling a Task With Fixed Rate and Initial Delay
You can use initialDelay
parameter with fixedRate
and fixedDelay
to delay the first execution of the task with the specified number of milliseconds.
In the following example, the first execution of the task will be delayed by 5 seconds and then it will be executed normally at a fixed interval of 2 seconds -
@Scheduled(fixedRate = 2000, initialDelay = 5000)
public void scheduleTaskWithInitialDelay() {
logger.info("Fixed Rate Task with Initial Delay Schedule : " + dateTimeFormatter.format(LocalDateTime.now()));
}
Output :
Fixed Rate Task with Initial Delay Schedule : 14:39:10
Fixed Rate Task with Initial Delay Schedule : 14:39:12
Fixed Rate Task with Initial Delay Schedule : 14:39:14
Fixed Rate Task with Initial Delay Schedule : 14:39:16
...
...
4. Scheduling a Task using Cron Expression
If the above simple parameters can not fulfill your needs, then you can use cron expressions to schedule the execution of your tasks.
In the following example, I have scheduled the task to be executed every minute -
@Scheduled(cron = "0 * * * * ?")
public void scheduleTaskWithCronExpression() {
logger.info("Cron task Schedule : " + dateTimeFormatter.format(LocalDateTime.now()));
}
Output :
Cron task Schedule : 14:42:00
Cron task Schedule : 14:43:00
Cron task Schedule : 14:44:00
...
...
Running @Scheduled Tasks in a Custom Thread Pool
By default, all the @Scheduled
tasks are executed in a default thread pool of size one created by Spring.
You can verify that by logging the name of the current thread in all the methods -
logger.info("Current Thread : {}", Thread.currentThread().getName());
Output :
Current Thread : scheduling-1
But hey, You can create your own thread pool and configure Spring to use that thread pool for executing all the scheduled tasks.
Create a new package config
inside com.example
, and then create a new class called SchedulerConfig
inside config
package with the following contents -
package com.example.config;import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;@Configuration
public class SchedulerConfig implements SchedulingConfigurer {
private final int POOL_SIZE = 10; @Override
public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler(); threadPoolTaskScheduler.setPoolSize(POOL_SIZE);
threadPoolTaskScheduler.setThreadNamePrefix("my-scheduled-task-pool-");
threadPoolTaskScheduler.initialize(); scheduledTaskRegistrar.setTaskScheduler(threadPoolTaskScheduler);
}
}
That’s all you need to do for configuring Spring to use your own thread pool instead of the default one.
If you log the name of the current thread in the scheduled methods now, you’ll get the output like so -
Current Thread : my-scheduled-task-pool-2
Current Thread : my-scheduled-task-pool-1
Current Thread : my-scheduled-task-pool-4
...
Final Output :
Current Thread : my-scheduled-task-pool-1
Fixed Rate Task with Initial Delay Schedule : 14:50:52
Current Thread : my-scheduled-task-pool-4
Fixed Rate Schedule : 14:50:53
Current Thread : my-scheduled-task-pool-3
Fixed Rate Task with Initial Delay Schedule : 14:50:54
Current Thread : my-scheduled-task-pool-6
Fixed Rate Schedule : 14:50:55
Current Thread : my-scheduled-task-pool-7
Fixed Rate Task with Initial Delay Schedule : 14:50:56
Current Thread : my-scheduled-task-pool-2
Fixed Rate Schedule : 14:50:57
Current Thread : my-scheduled-task-pool-5
Fixed Rate Task with Initial Delay Schedule : 14:50:58
Current Thread : my-scheduled-task-pool-9
Fixed Delay Schedule : 14:50:58
Current Thread : my-scheduled-task-pool-8
Fixed Rate Schedule : 14:50:59
Current Thread : my-scheduled-task-pool-10
Cron task Schedule : 14:51:00
Current Thread : my-scheduled-task-pool-4
Fixed Rate Task with Initial Delay Schedule : 14:51:00
Current Thread : my-scheduled-task-pool-3
Fixed Rate Schedule : 14:51:01
Current Thread : my-scheduled-task-pool-6
Fixed Rate Task with Initial Delay Schedule : 14:51:02
Current Thread : my-scheduled-task-pool-7
Fixed Rate Schedule : 14:51:03
Current Thread : my-scheduled-task-pool-2
Fixed Rate Task with Initial Delay Schedule : 14:51:04
Current Thread : my-scheduled-task-pool-1
Fixed Rate Schedule : 14:51:05
Current Thread : my-scheduled-task-pool-5
Fixed Delay Schedule : 14:51:05
Current Thread : my-scheduled-task-pool-9
Fixed Rate Task with Initial Delay Schedule : 14:51:06
Current Thread : my-scheduled-task-pool-10
...
...