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.