skip to content

Task Scheduling (@Scheduled)

@Scheduled with fixedRate, fixedDelay or a cron expression runs periodic work inside the application. What separates candidates is the single-threaded default scheduler and what happens when one task overruns — or when you deploy two instances.

part ofSpring Frameworkoverview, primer and where to startread it →
on this pageshow

questions

5

How do you schedule a recurring background task in Spring, and what two things are required to make it run?

level: juniorimportance: must knowfreq 75%

answer

  1. @EnableScheduling turns it on
  2. @Scheduled marks the method
  3. void + no-args required
  4. ScheduledAnnotationBeanPostProcessor scans
  5. must be a Spring bean

basics

~10 s

Add @EnableScheduling to a @Configuration class to turn scheduling on, then put @Scheduled (with fixedRate, fixedDelay, or cron) on a no-argument, void method of a Spring bean. Spring calls it automatically on a timer.

solid answer

~40 s

Two pieces are required. First, @EnableScheduling on a @Configuration (or @SpringBootApplication) class; it registers the infrastructure (a ScheduledAnnotationBeanPostProcessor) that scans beans for scheduled methods. Second, an @Scheduled annotation on a method of a Spring-managed bean, giving a trigger: fixedRate, fixedDelay, or a cron expression. The method must be void and take no arguments, since Spring invokes it reflectively with no way to pass parameters or use a return value. Without @EnableScheduling nothing runs even if @Scheduled is present. In Spring Boot the scheduling classes are on the classpath, but you still add @EnableScheduling yourself; it is not on by default. The target must be a real Spring bean (@Component, @Service, etc.) so the post-processor can detect it.

code

java · 17 lines
java
@SpringBootApplication
@EnableScheduling
public class App {
    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }
}

@Component
public class CleanupJob {

    // void, no args, one timing strategy
    @Scheduled(fixedRate = 60_000)
    public void purgeExpired() {
        // ... runs every 60 seconds
    }
}

go deeper

for a junior

Must know the two annotations and that the method is void/no-args.

for a middle

Should explain the post-processor scan and the silent no-op when @EnableScheduling is missing.

for a senior

Should mention multi-instance duplication and that it is not a distributed scheduler.

for a principal

Frames @Scheduled as in-process only; reaches for ShedLock/leader election for cluster-wide single execution.

**What scheduling means here.** Spring's task-scheduling support lets you run a method automatically on a timer without writing your own `Thread`, `Timer`, or `ScheduledExecutorService`. You annotate a method and Spring invokes it for you on a background thread. **The two required parts:** 1. **`@EnableScheduling`** — placed on a `@Configuration` class (or your `@SpringBootApplication`, which is itself a configuration). It imports the scheduling infrastructure, most importantly the `ScheduledAnnotationBeanPostProcessor`. A *bean post-processor* is a Spring hook that inspects every bean as it is created; this one scans each bean's methods for `@Scheduled` and registers the ones it finds with a `TaskScheduler`. If you forget `@EnableScheduling`, your `@Scheduled` methods are silently ignored — no error, they just never fire. This is the single most common beginner mistake. 2. **`@Scheduled`** — on a method of a Spring-managed bean. You must give it exactly one timing strategy: `fixedRate`, `fixedDelay`, or `cron` (optionally with `initialDelay`). **Constraints on the method.** The method must (a) return `void` and (b) take **no arguments**. Spring calls it by reflection with nothing to pass in and ignores any return value, so a non-void or parameterized method is rejected at startup with an `IllegalStateException`. The method may be `public` or not — Spring can invoke non-public methods, though `public` is conventional. **The bean must be managed by Spring.** `@Scheduled` on a plain `new`-ed object does nothing; only beans that pass through the container are scanned. Also note that if the bean is proxied (e.g. it also has `@Transactional`), scheduling still works because the post-processor operates on the bean instance. **Spring Boot specifics.** The starter puts `spring-context` (which contains scheduling) on the classpath, but Boot does **not** auto-enable scheduling. You add `@EnableScheduling` explicitly, typically on the main application class. **Where the thread comes from.** By default Spring creates a single-threaded scheduler if you don't define your own `TaskScheduler`/`ThreadPoolTaskScheduler` bean — important once you have more than one scheduled task (covered in the pool-sizing question). **When to use it.** Good for periodic in-process jobs: cache eviction, cleanup, polling, metrics flushing, sending digest emails. It is **not** a distributed scheduler — in a multi-instance deployment every instance runs the job, so you need a lock (e.g. ShedLock) or leader election if the job must run once cluster-wide.

  • You added @Scheduled but the method never runs and there is no error. What is the first thing you check?
    That @EnableScheduling is present on a @Configuration/@SpringBootApplication class. Without it the ScheduledAnnotationBeanPostProcessor is never registered, so @Scheduled methods are silently ignored. Also confirm the class is an actual Spring bean.
  • Can a @Scheduled method take parameters or return a value?
    No. It must be void and take no arguments. Spring invokes it reflectively with nothing to pass and no consumer for a return value; a non-void or parameterized method fails at startup with an IllegalStateException.

saying these in an interview costs you the question

  • Thinking Spring Boot enables scheduling automatically without @EnableScheduling
  • Putting @Scheduled on a non-bean (new-ed object) and expecting it to run
  • Claiming the method can accept arguments or return a result
  • Believing a missing @EnableScheduling produces a startup error rather than silent no-op

context

open as a page

Explain the difference between @Scheduled fixedRate, fixedDelay, and initialDelay. When do fixedRate executions overlap or pile up?

level: middleimportance: must knowfreq 80%

basics

~20 s

fixedDelay measures the gap between the end of one run and the start of the next, so runs never overlap. fixedRate measures from the start of one run to the start of the next, regardless of how long the run takes. initialDelay delays only the very first execution.

open as a page

What is the default thread model for @Scheduled, why is it a common production pitfall, and how do you size a ThreadPoolTaskScheduler correctly?

level: seniorimportance: must knowfreq 70%

basics

~20 s

By default Spring uses a single-threaded scheduler, so all @Scheduled methods share one thread. A slow or blocked task delays every other scheduled task. Fix it by defining a ThreadPoolTaskScheduler bean with a pool size big enough for your concurrent jobs.

open as a page

Explain Spring's cron support: the field layout, the zone attribute, and how CronExpression is used. How does Spring's cron differ from classic Unix cron?

level: middleimportance: should knowfreq 60%

basics

~20 s

@Scheduled(cron = "...") uses a six-field expression: second, minute, hour, day-of-month, month, day-of-week. Unlike Unix cron it has a leading seconds field. Add zone = "Europe/Paris" to pin the time zone, and use the special value "-" to disable the task.

open as a page

What happens when a @Scheduled fixedDelay/fixedRate method throws an unchecked exception versus a cron method? How should you make scheduled jobs resilient?

level: principalimportance: should knowfreq 45%

basics

~20 s

An uncaught exception from a fixedDelay or fixedRate task is logged but the schedule keeps running — future executions still fire. Only if you use a one-shot future would it stop. Make jobs resilient by catching and handling exceptions inside the method rather than letting them propagate.

open as a page