The @Scheduled Annotation in Spring

1. Overview

In this article we’ll discuss the Spring @Scheduled annotation – we will illustrate how it can be used to configure and schedule tasks.

The simple rules that need to be followed to annotate a method with @Scheduled are:

  • a method should have void return type

  • a method should not accept any parameters

Further reading:

How To Do @Async in Spring

How to enable and use @Async in Spring – from the very simple config and basic usage to the more complex executors and exception handling strategies.

Read more

A Guide to the Spring Task Scheduler

A quick and practical guide to scheduling in Spring with Task Scheduler

Read more

Scheduling in Spring with Quartz

Quick introduction to working with Quartz in Spring.

Read more

2. Enable Support for Scheduling

To enable the support for scheduling tasks and the @Scheduled annotation in Spring – we can use the Java enable-style annotation:

@Configuration
@EnableScheduling
public class SpringConfig {
    ...
}

Or we can do the same in XML:

<task:annotation-driven>

3. Schedule a Task at Fixed Delay

Let’s start by configuring a task to run after a fixed delay:

@Scheduled(fixedDelay = 1000)
public void scheduleFixedDelayTask() {
    System.out.println(
      "Fixed delay task - " + System.currentTimeMillis() / 1000);
}

In this case, the duration between the end of last execution and the start of next execution is fixed. The task always waits until the previous one is finished.

This option should be used when it’s mandatory that the previous execution is completed before running again.

4. Schedule a Task at a Fixed Rate

Let’s now execute a task at a fixed interval of time:

@Scheduled(fixedRate = 1000)
public void scheduleFixedRateTask() {
    System.out.println(
      "Fixed rate task - " + System.currentTimeMillis() / 1000);
}

This option should be used when each execution of the task is independent.

Note that scheduled tasks don’t run in parallel by default. So even if we used fixedRate, the next task won’t be invoked until the previous one is done.

If we want to support parallel behavior in scheduled tasks, we need to add the @Async annotation:

@EnableAsync
public class ScheduledFixedRateExample {
    @Async
    @Scheduled(fixedRate = 1000)
    public void scheduleFixedRateTaskAsync() throws InterruptedException {
        System.out.println(
          "Fixed rate task async - " + System.currentTimeMillis() / 1000);
        Thread.sleep(2000);
    }

}

Now this asynchronous task will be invoked each second, even if the previous task isn’t done.

5. Fixed Rate vs Fixed Delay

We can run a scheduled task using Spring’s @Scheduled annotation but based on the properties fixedDelay and fixedRate the nature of execution changes.

The fixedDelay property makes sure that there is a delay of n millisecond between the finish time of an execution of a task and the start time of the next execution of the task.

This property is specifically useful when we need to make sure that only one instance of the task runs all the time. For dependent jobs, it is quite helpful.

The fixedRate property runs the scheduled task at every n millisecond. It doesn’t check for any previous executions of the task.

This is useful when all executions of the task are independent. If we don’t expect to exceed the size of the memory and the thread pool, fixedRate should be quite handy.

But, if the incoming tasks do not finish quickly, it’s possible they end up with “Out of Memory exception”.

6. Schedule a Task with Initial Delay

Next – let’s schedule a task with a delay (in milliseconds):

@Scheduled(fixedDelay = 1000, initialDelay = 1000)
public void scheduleFixedRateWithInitialDelayTask() {

    long now = System.currentTimeMillis() / 1000;
    System.out.println(
      "Fixed rate task with one second initial delay - " + now);
}

Note how we’re using both fixedDelay as well as initialDelay in this example. The task will be executed a first time after the initialDelay value – and it will continue to be executed according to the fixedDelay.

This option comes handy when the task has a set-up that needs to be completed.

7. Schedule a Task Using Cron Expressions

Sometimes delays and rates are not enough, and we need the flexibility of a cron expression to control the schedule of our tasks:

@Scheduled(cron = "0 15 10 15 * ?")
public void scheduleTaskUsingCronExpression() {

    long now = System.currentTimeMillis() / 1000;
    System.out.println(
      "schedule tasks using cron jobs - " + now);
}

Note – in this example, that we’re scheduling a task to be executed at 10:15 AM on the 15th day of every month.

8. Parameterizing the Schedule

Hardcoding these schedules is simple, but usually, you need to be able to control the schedule without re-compiling and re-deploying the entire app.

We’ll make use of Spring Expressions to externalize the configuration of the tasks – and we’ll store these in properties files:

A fixedDelay task:

@Scheduled(fixedDelayString = "${fixedDelay.in.milliseconds}")

A fixedRate task:

@Scheduled(fixedRateString = "${fixedRate.in.milliseconds}")

A cron expression based task:

@Scheduled(cron = "${cron.expression}")

9. Configuring Scheduled Tasks Using XML

Spring also provides XML way of configuring the scheduled tasks – here is the XML configuration to set these up:

<!-- Configure the scheduler -->
<task:scheduler id="myScheduler" pool-size="10" />

<!-- Configure parameters -->
<task:scheduled-tasks scheduler="myScheduler">
    <task:scheduled ref="beanA" method="methodA"
      fixed-delay="5000" initial-delay="1000" />
    <task:scheduled ref="beanB" method="methodB"
      fixed-rate="5000" />
    <task:scheduled ref="beanC" method="methodC"
      cron="*/5 * * * * MON-FRI" />
</task:scheduled-tasks>

10. Conclusion

In this article, we understood the way to configure and use the @Scheduled annotation.

We covered the process to enable scheduling and various ways of configuring scheduling task patterns.

The examples shown can be found over on GitHub.

Leave a Reply

Your email address will not be published.