Table of contents
1.
Introduction
2.
Implementation
2.1.
Enabling Support for Scheduling
3.
Scheduling Tasks Using a Cron Expression
4.
Scheduling Tasks at a Fixed Rate
5.
Scheduling Tasks to Run at a Fixed Delay
5.1.
Setting Delay or Rate Dynamically at Runtime  
5.1.1.
Steps to Set Delay or Rate Dynamically  
5.2.
Running Tasks in Parallel  
5.2.1.
Steps to Run Tasks in Parallel  
6.
Schedule a Task Using Cron Expressions
7.
Parameterizing the Schedule
8.
Configuring Scheduled Tasks Using XML  
8.1.
Steps to Configure Scheduled Tasks Using XML  
9.
Fixed Rate vs Fixed Delay
10.
Frequently Asked Questions
10.1.
Can I use multiple @Scheduled annotations in a single class? 
10.2.
What happens if a task takes longer than the scheduled interval? 
10.3.
How do I test scheduled tasks? 
11.
Conclusion
Last Updated: Jan 18, 2025
Easy

Scheduler in Spring Boot

Author Gaurav Gandhi
0 upvote
Career growth poll
Do you think IIT Guwahati certified course can help you in your career?

Introduction

Scheduler in Spring Boot is a feature that allows you to run tasks at specific times or intervals without needing to manually trigger them. This is useful for automating tasks like sending emails, cleaning up old data, or performing regular database backups. With Spring Boot, setting up a scheduler is simple and efficient.

Scheduler in Spring Boot

This article will discuss implementing schedulers in Spring Boot, explaining different scheduling techniques, their implementations, and how to parameterize schedules effectively. 

Implementation

Spring Boot makes scheduling simple with the @Scheduled annotation. You need to enable scheduling and define when tasks should execute. Below, we’ll discuss the different ways to schedule tasks and how to implement them.

Enabling Support for Scheduling

To enable scheduling in your Spring Boot application, you must annotate your configuration class with @EnableScheduling. This ensures Spring’s task scheduler is initialized.

Example:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@EnableScheduling
public class SchedulerApplication {
    public static void main(String[] args) {
        SpringApplication.run(SchedulerApplication.class, args);
    }
}

Here, @EnableScheduling activates Spring’s scheduling capability. Once enabled, you can use the @Scheduled annotation to create scheduled tasks.

Scheduling Tasks Using a Cron Expression

Cron expressions are powerful tools to define complex schedules. They consist of six fields representing seconds, minutes, hours, day of the month, month, and day of the week.

Example:

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
public class CronScheduler {
    @Scheduled(cron = "0 0/5 * * * ?")
    public void executeTask() {
        System.out.println("Task executed at: " + java.time.LocalTime.now());
    }
}


Explanation:

  • 0 0/5 * * * ?: This cron expression means the task will run every 5 minutes.
     
  • @Scheduled: Marks the method for scheduling.


Output:

Every 5 minutes, the following will print:
Task executed at: HH:MM:SS

Scheduling Tasks at a Fixed Rate

A fixed rate scheduling ensures that tasks execute at regular intervals, regardless of the previous task’s completion.

Example:

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
public class FixedRateScheduler {
    @Scheduled(fixedRate = 5000)
    public void executeFixedRateTask() {
        System.out.println("Fixed rate task executed at: " + java.time.LocalTime.now());
    }
}


Explanation:

  • fixedRate = 5000: The task runs every 5000 milliseconds (5 seconds).
     
  • Tasks will run at consistent intervals, regardless of their duration.


Output:

Every 5 seconds:
Fixed rate task executed at: HH:MM:SS

Scheduling Tasks to Run at a Fixed Delay

Fixed delay scheduling ensures that a task starts a fixed amount of time after the previous task finishes.

Example:

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
public class FixedDelayScheduler {
    @Scheduled(fixedDelay = 3000)
    public void executeFixedDelayTask() {
        System.out.println("Fixed delay task executed at: " + java.time.LocalTime.now());
    }
}

Explanation:

fixedDelay = 3000: The task starts 3 seconds after the previous task completes.
 

Useful when tasks may vary in execution time.


Output:

After a 3-second delay from the last task completion:
Fixed delay task executed at: HH:MM:SS

Setting Delay or Rate Dynamically at Runtime  

In some cases, you might need to change the delay or rate of a scheduled task while the application is running. For example, you may want to adjust the polling interval of an API based on external conditions. Spring Boot allows you to achieve this by using a `ScheduledTaskRegistrar` & custom logic to update the scheduling parameters dynamically.  

Steps to Set Delay or Rate Dynamically  


1. Create a Custom Scheduler Configuration  

   Use the `SchedulingConfigurer` interface to create a custom scheduler configuration.  


2. Use `ScheduledTaskRegistrar` to Register Tasks  

The `ScheduledTaskRegistrar` class allows you to programmatically register tasks with dynamic delays or rates.  


3. Update the Delay or Rate at Runtime  

Use a method to update the scheduling parameters dynamically.  


For example: 


 Java Class (`DynamicSchedulerConfig.java`)  



import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.support.PeriodicTrigger;

import java.util.concurrent.TimeUnit;

@Configuration
public class DynamicSchedulerConfig implements SchedulingConfigurer {

    private int initialDelay = 5000; // Initial delay of 5 seconds
    private int updatedDelay = 10000; // Updated delay of 10 seconds

    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        taskRegistrar.addTriggerTask(
            () -> System.out.println("Dynamic Task :: Execution Time - " + System.currentTimeMillis()),
            triggerContext -> {
                PeriodicTrigger trigger = new PeriodicTrigger(initialDelay, TimeUnit.MILLISECONDS);
                return trigger.nextExecutionTime(triggerContext);
            }
        );
    }
    // Method to update the delay dynamically
    public void updateDelay(int newDelay) {
        this.initialDelay = newDelay;
        System.out.println("Delay updated to: " + newDelay + " milliseconds");
    }
}


Java Class (`DynamicSchedulerController.java`)  

To demonstrate how to update the delay dynamically, let’s create a simple REST controller that allows us to change the delay at runtime.  

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class DynamicSchedulerController {

    @Autowired
    private DynamicSchedulerConfig dynamicSchedulerConfig;

    @GetMapping("/updateDelay")
    public String updateDelay(@RequestParam int delay) {
        dynamicSchedulerConfig.updateDelay(delay);
        return "Delay updated to: " + delay + " milliseconds";
    }
}


In this Code :  

1. `DynamicSchedulerConfig`:  

   - Implements `SchedulingConfigurer` to configure tasks programmatically.  

   - Uses `ScheduledTaskRegistrar` to register a task with a dynamic delay.  

   - The `PeriodicTrigger` class is used to define the delay.  


2. `DynamicSchedulerController`:  

   - Provides an endpoint (`/updateDelay`) to update the delay dynamically.  

   - Calls the `updateDelay` method in `DynamicSchedulerConfig` to change the delay.  


3. How It Works:  

   - When the application starts, the task runs with an initial delay of 5 seconds.  

   - You can call the `/updateDelay` endpoint (e.g., `http://localhost:8080/updateDelay?delay=15000`) to change the delay to 15 seconds.  


Key Points to Remember  

1. Dynamic scheduling is useful when you need to adjust task intervals based on runtime conditions.  
 

2. The `ScheduledTaskRegistrar` & `PeriodicTrigger` classes are key to implementing dynamic scheduling.  
 

3. You can extend this approach to update rates or other scheduling parameters dynamically.  

Running Tasks in Parallel  

By default, Spring Boot runs scheduled tasks in a single-threaded manner. This means that if one task takes a long time to execute, it can delay other tasks. To avoid this, you can configure Spring Boot to run tasks in parallel using a thread pool. This allows multiple tasks to execute simultaneously, improving performance & responsiveness.  

Steps to Run Tasks in Parallel  


1. Enable Async Scheduling  

   Use the `@EnableAsync` annotation to enable asynchronous execution of tasks.  


2. Configure a Thread Pool  

   Define a thread pool using the `TaskExecutor` interface or its implementations.  


3. Annotate Scheduled Methods with `@Async`  

   Use the `@Async` annotation to mark methods that should run asynchronously.  


Let’s take a complete example:  


Java Class (`ParallelSchedulerConfig.java`)  

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.Executor;

@Configuration
@EnableAsync // Enable asynchronous execution
public class ParallelSchedulerConfig {

    @Bean(name = "taskExecutor")
    public Executor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(5); // Set the core pool size
        executor.setMaxPoolSize(10); // Set the maximum pool size
        executor.setQueueCapacity(25); // Set the queue capacity
        executor.setThreadNamePrefix("SchedulerThread-"); // Set thread name prefix
        executor.initialize();
        return executor;
    }
}


 Java Class (`ParallelScheduledTasks.java`)  

import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component
public class ParallelScheduledTasks {

    @Async("taskExecutor") // Use the configured thread pool
    @Scheduled(fixedRate = 2000) // Run every 2 seconds
    public void taskOne() throws InterruptedException {
        System.out.println("Task One :: Execution Time - " + System.currentTimeMillis() + " :: Thread - " + Thread.currentThread().getName());
        Thread.sleep(3000); // Simulate a long-running task
    }
    @Async("taskExecutor") // Use the configured thread pool
    @Scheduled(fixedRate = 2000) // Run every 2 seconds
    public void taskTwo() throws InterruptedException {
        System.out.println("Task Two :: Execution Time - " + System.currentTimeMillis() + " :: Thread - " + Thread.currentThread().getName());
        Thread.sleep(3000); // Simulate a long-running task
    }
}


In this Code: 

1. `ParallelSchedulerConfig`:  

  • Configures a thread pool using `ThreadPoolTaskExecutor`.  
     
  • Sets the core pool size, maximum pool size, & queue capacity.  
     
  • The `@EnableAsync` annotation enables asynchronous execution.  


2. `ParallelScheduledTasks`:  

  • Contains two scheduled tasks (`taskOne` & `taskTwo`) that run every 2 seconds.  
     
  • The `@Async` annotation ensures that each task runs in a separate thread from the thread pool.  
     
  • The `Thread.sleep(3000)` simulates a long-running task to demonstrate parallel execution.  


3. How It Works:  

  • Both tasks run every 2 seconds, but they don’t block each other because they execute in separate threads.  
     
  • The thread pool ensures that multiple tasks can run simultaneously without delays.  

 

Key Points to Remember  

1. Running tasks in parallel improves performance, especially for long-running tasks.  
 

2. Use the `@Async` annotation & configure a thread pool to enable parallel execution.  
 

3. Be mindful of thread pool settings (core pool size, max pool size, & queue capacity) to avoid resource exhaustion. 

Schedule a Task Using Cron Expressions

Cron expressions allow for more granular control over scheduling, including specific times or days. Here’s an example of scheduling a task to run every Monday at 10 AM.

Example:

@Component
public class WeeklyReportScheduler {

    @Scheduled(cron = "0 0 10 * * MON")
    public void generateWeeklyReport() {
        System.out.println("Weekly report generated at: " + java.time.LocalTime.now());
    }
}


Explanation:

0 0 10 * * MON: Executes the task at 10:00 AM every Monday.

Perfect for tasks like generating reports or backups.

Parameterizing the Schedule

Dynamic schedules allow developers to modify task timings without changing code. Use configuration files or databases to achieve this.

Example:


application.properties:

scheduler.fixedRate=5000
scheduler.fixedDelay=3000


Implementation:

import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
public class DynamicScheduler {

    @Value("${scheduler.fixedRate}")
    private long fixedRate;

    @Value("${scheduler.fixedDelay}")
    private long fixedDelay;

    @Scheduled(fixedRateString = "${scheduler.fixedRate}")
    public void fixedRateTask() {
        System.out.println("Dynamic fixed rate task at: " + java.time.LocalTime.now());
    }

    @Scheduled(fixedDelayString = "${scheduler.fixedDelay}")
    public void fixedDelayTask() {
        System.out.println("Dynamic fixed delay task at: " + java.time.LocalTime.now());
    }
}


Explanation:

  • The @Value annotation reads values from the application.properties file.
     
  • Task timings can be modified without changing the code.

Configuring Scheduled Tasks Using XML  

While Spring Boot heavily relies on annotations for scheduling tasks, it also supports XML-based configuration for those who prefer it or need to maintain legacy code. XML configuration allows you to define scheduled tasks without using annotations like `@Scheduled`.  

Steps to Configure Scheduled Tasks Using XML  


1. Enable Scheduling in XML  

First, you need to enable scheduling in your Spring configuration file (`applicationContext.xml` or any other XML file). This is done using the `<task:annotation-driven>` tag.  


2. Define the Bean  

Create a bean for the class that contains the scheduled tasks.  


3. Configure the Task  

Use the `<task:scheduled-tasks>` tag to define the tasks & their scheduling details.  


Let’s take a complete example:  


XML Configuration File (`applicationContext.xml`)  

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:task="http://www.springframework.org/schema/task"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/task
           http://www.springframework.org/schema/task/spring-task.xsd">

    <!-- Enable scheduling -->
    <task:annotation-driven/>

    <!-- Define the bean -->
    <bean id="scheduledTasks" class="com.example.ScheduledTasks"/>

    <!-- Configure the task -->
    <task:scheduled-tasks>
        <!-- Run every 5 seconds -->
        <task:scheduled ref="scheduledTasks" method="taskWithFixedRate" fixed-rate="5000"/>
        <!-- Run 5 seconds after the previous task completes -->
        <task:scheduled ref="scheduledTasks" method="taskWithFixedDelay" fixed-delay="5000"/>
    </task:scheduled-tasks>
</beans>


Java Class (`ScheduledTasks.java`)  

package com.example;

public class ScheduledTasks {

    public void taskWithFixedRate() {
        System.out.println("Fixed Rate Task (XML) :: Execution Time - " + System.currentTimeMillis());
    }
    public void taskWithFixedDelay() {
        System.out.println("Fixed Delay Task (XML) :: Execution Time - " + System.currentTimeMillis());
    }
}

In this Code  

1. `<task:annotation-driven>`: Enables scheduling in the Spring application.  
 

2. `<bean>`: Defines the bean for the `ScheduledTasks` class.  
 

3. `<task:scheduled-tasks>`: Configures the tasks & their scheduling details.  
 

   - `ref`: Refers to the bean ID.  
 

   - `method`: Specifies the method to be executed.  
 

   - `fixed-rate` & `fixed-delay`: Define the scheduling intervals.  
 

 Key Points to Remember  

1. XML configuration is useful when you want to avoid annotations or need to externalize configuration.  
 

2. It’s a good practice to use XML for scheduling if you’re working with legacy systems or need to manage configurations outside the code.  
 

3. You can mix XML-based & annotation-based scheduling in the same application.  

Fixed Rate vs Fixed Delay

ParametersFixed RateFixed Delay
Task ExecutionTasks are executed at a fixed interval, regardless of how long each task takes to complete.The delay between task executions is fixed, meaning the next task starts after the specified delay.
Task OverlapIf a task takes longer than the specified interval, the next execution will start immediately after the current one finishes.If a task takes longer than the specified delay, the next execution starts after the delay has elapsed.
Use CaseSuitable for tasks that need to run at strict intervals, such as polling or monitoring.Suitable for tasks that require a certain cooldown period between executions, such as rate-limited API calls or resource-intensive operations.

Frequently Asked Questions

Can I use multiple @Scheduled annotations in a single class? 

Yes, you can have multiple methods annotated with @Scheduled in the same class.

What happens if a task takes longer than the scheduled interval? 

If using fixedRate, tasks may overlap. If using fixedDelay, the next task will wait until the previous one completes.

How do I test scheduled tasks? 

You can test scheduled tasks using Spring’s TaskScheduler interface or mock the behavior in unit tests.

Conclusion

Schedulers in Spring Boot are an efficient way to automate tasks like sending notifications, generating reports, or running periodic jobs. By understanding cron expressions, fixed-rate, and fixed-delay scheduling, you can implement flexible and dynamic schedules in your applications. 

You can also check out our other blogs on Code360.

Live masterclass