Start Learning
Javaneer
Back to stage
Module 6·Reactive & Messaging

Async & Scheduling

Run work off the request thread with @Async, and run jobs on a timer with @Scheduled.

14 min readIntermediate
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.

Hand it to an assistant and move on

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.

Async or scheduled?

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.
Was this lesson helpful?
Edit this page on GitHub