Async & Scheduled Tasks

Offload slow work with @EnableAsync + @Async (returning CompletableFuture ), and run jobs on a timer with @EnableScheduling + @Scheduled .

Learn Async & Scheduled Tasks in our free Java course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a quick reference.

Part of the free Java course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.

You should understand Spring beans and proxies, and ideally have met CompletableFuture . Having documented your API with OpenAPI & springdoc rounds out the service.

💡 Analogy: In a busy kitchen the head chef does not stand and watch the dishwasher run. They hand it off and carry on. @Async is that hand-off: slow, independent work goes to a pool of helper threads while the request thread is freed up. @Scheduled is the kitchen timer — jobs that fire on their own at set times.

You decide what to offload and when things should fire; Spring's executors and scheduler do the rest.

Turn on support with @EnableAsync and @EnableScheduling , and define a ThreadPoolTaskExecutor bean to control pool size and naming.

Annotate a method @Async . Return CompletableFuture<T> when you need the result, or void for fire-and-forget.

fixedRate measures from each start, fixedDelay from each finish, and cron gives calendar-style schedules.

@Async works via a proxy. Calling an async method from within the same class skips the proxy, so it runs synchronously. Call it through another bean instead.

To make the hand-off tangible, here is a plain-Java stand-in using a thread pool and CompletableFuture — exactly the model @Async builds on — with real output.

Answer: a CompletableFuture<T> (or the older Future<T> ).

Answer: fixedRate measures from each start ; fixedDelay from each finish (so it never overlaps).

Answer: the self-invocation bypasses the Spring proxy that adds the async behaviour.

You now know how to offload work with @EnableAsync and @Async (returning CompletableFuture), configure a ThreadPoolTaskExecutor, schedule jobs with @EnableScheduling and @Scheduled (fixedRate/fixedDelay/cron), handle async exceptions, and avoid the self-invocation pitfall.

That completes the Spring & Enterprise track — you now have the tools to build, document, migrate and scale a production Spring Boot service.

Practice quiz

Which annotation turns on Spring's asynchronous method support?

  • @EnableAsync
  • @Async
  • @Scheduled
  • @EnableScheduling

Answer: @EnableAsync. @EnableAsync (on a @Configuration class) activates the proxy machinery that makes @Async methods run on a separate thread.

What does putting @Async on a method do?

  • Schedules it on a timer
  • Caches its result
  • Runs it on a separate thread, returning to the caller immediately
  • Makes it transactional

Answer: Runs it on a separate thread, returning to the caller immediately. @Async makes Spring invoke the method on a thread from a task executor, so the caller is not blocked while it runs.

What should an @Async method that returns a value return?

  • An Optional<T>
  • A CompletableFuture<T> (or Future<T>)
  • void only
  • A raw object

Answer: A CompletableFuture<T> (or Future<T>). To hand a result back to the caller, an @Async method returns CompletableFuture<T> (or the older Future), which the caller can wait on or compose.

Which executor type backs Spring's async tasks and is typically configured?

  • ForkJoinPool only
  • SingleThreadExecutor only
  • ScheduledThreadPool
  • ThreadPoolTaskExecutor

Answer: ThreadPoolTaskExecutor. ThreadPoolTaskExecutor is Spring's configurable thread pool; you define one as a bean to control pool size, queue capacity and thread naming.

Which annotation enables scheduled tasks?

  • @EnableScheduling
  • @EnableAsync
  • @Scheduled
  • @Timer

Answer: @EnableScheduling. @EnableScheduling activates support for @Scheduled methods; without it, scheduled methods are ignored.

What is the difference between fixedRate and fixedDelay on @Scheduled?

  • They are identical
  • fixedRate measures from each start; fixedDelay measures from each finish
  • fixedDelay runs once only
  • fixedRate uses cron syntax

Answer: fixedRate measures from each start; fixedDelay measures from each finish. fixedRate triggers every N ms from the previous start time, while fixedDelay waits N ms after the previous run finishes before starting again.

Which @Scheduled attribute uses cron expressions for complex schedules?

  • initialDelay
  • fixedRate
  • fixedDelay
  • cron

Answer: cron. The cron attribute accepts a cron expression (such as every weekday at 8am), giving calendar-style scheduling beyond simple intervals.

How do you handle an exception thrown by a void @Async method?

  • A try/catch around the call site catches it
  • It cannot throw
  • With an AsyncUncaughtExceptionHandler
  • Spring rethrows it to main()

Answer: With an AsyncUncaughtExceptionHandler. A void @Async method runs on another thread, so the caller cannot catch its exception; you provide an AsyncUncaughtExceptionHandler. A CompletableFuture-returning method carries the exception in the future.

Why does calling an @Async method from another method in the SAME class often run synchronously?

  • A configuration bug
  • Self-invocation bypasses the Spring proxy
  • @Async is disabled by default
  • The thread pool is empty

Answer: Self-invocation bypasses the Spring proxy. @Async works via a proxy. An internal self-call goes straight to the target object, skipping the proxy, so the async behaviour is bypassed.

Without @EnableAsync, what happens to a method annotated @Async?

  • It runs synchronously, like a normal method
  • It still runs asynchronously
  • The application fails to start
  • It is never called

Answer: It runs synchronously, like a normal method. If async support is not enabled, the @Async annotation is ignored and the method simply runs on the calling thread.