Async & Scheduling
Run work off the request thread with @Async, and run jobs on a timer with @Scheduled.
On this page
Not every "do it later" needs the full reactive stack. Two simple Spring annotations cover a
huge amount of everyday asynchronous work: @Async to run a method off the caller's
thread, and @Scheduled to run a method on a timer.
@Async: run it off the request thread
When BookVault records a loan, sending a notification email shouldn't make the borrower wait for the mail server. Move that work to a background thread:
@Configuration
@EnableAsync
class AsyncConfig {}
@Service
class NotificationService {
@Async
void sendBorrowConfirmation(Loan loan) {
// runs on a separate thread; the caller returns immediately
}
}The caller fires sendBorrowConfirmation(loan) and continues instantly; the method runs on a
background executor. Return void for fire-and-forget, or CompletableFuture<T> if you need
the result later.
When a manager needs a report compiled, they don't sit and watch it happen - they hand it to
an assistant and get back to their own work, checking in later if they need the result.
@Async is that assistant: the calling code delegates the slow task and carries on
immediately, instead of blocking until it's done.
@Scheduled: run it on a timer
For recurring jobs - marking loans overdue, refreshing a cache, sending nightly summaries -
@Scheduled runs a method automatically:
@Configuration
@EnableScheduling
class SchedulingConfig {}
@Service
class OverdueSweeper {
@Scheduled(fixedRate = 60_000) // every 60 seconds
void checkForOverdueLoans() { ... }
@Scheduled(cron = "0 0 2 * * *") // every day at 02:00
void nightlySummary() { ... }
}Use fixedRate/fixedDelay for "every N milliseconds," or a cron expression for
calendar-based schedules.
@Async needs a real boundary, like @Transactional
@Async works through a proxy (remember AOP), so calling an @Async method from within the
same class bypasses it and runs synchronously. Call it across beans. Also tune the executor -
the default can be unbounded; configure a sized thread pool for production.
For each BookVault task, choose @Async or @Scheduled: (1) email a borrow confirmation
without delaying the API response; (2) every night, flag loans whose due date has passed; (3)
regenerate a "most borrowed books" report every hour.
What does @Scheduled do?
Key takeaways
- @Async (with @EnableAsync) runs a method on a background thread so the caller returns immediately - great for fire-and-forget work like notifications.
- @Scheduled (with @EnableScheduling) runs a method on a timer: fixedRate/fixedDelay for intervals, cron for calendar schedules.
- Return void for fire-and-forget @Async, or CompletableFuture<T> to get the result later.
- @Async is proxy-based, so a self-invocation bypasses it; call across beans and size the executor pool.
- Use @Async for event-triggered off-thread work and @Scheduled for clock-driven recurring jobs.