Mastering Async and Scheduled Tasks in Spring Boot 3.2.5

This guide explains how to enable and use Spring Boot's @Async and @Scheduled annotations, configure various TaskExecutor and TaskScheduler implementations, leverage new Spring 6.1 pause/resume and virtual‑thread features, and apply graceful shutdown for both asynchronous and scheduled jobs.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Mastering Async and Scheduled Tasks in Spring Boot 3.2.5

1. Introduction

Spring provides powerful support for asynchronous and scheduled tasks. The @Async annotation runs a method in a separate thread and returns a Future or CompletableFuture to the caller. The @Scheduled annotation defines a timed task that can be configured via cron expressions or fixed rates, allowing efficient resource utilization.

2. Basic Usage

2.1 Asynchronous Task

@EnableAsync
public class AppConfig {}

@Service
public class EmailService {
    @Async
    public void sendMail() {
        // TODO
    }
}

Two steps enable async execution and annotate the method.

2.2 Scheduled Task

@EnableScheduling
public class AppConfig {}

@Component
public class StatisticsService {
    // Executes every day at midnight
    @Scheduled(cron = "0 0 * * ?")
    public void calcDayAmount() {
        // TODO
    }
}

Similarly, enable scheduling and annotate the method. Additional @Scheduled attributes (fixed delay, fixed rate, etc.) can be used.

3. TaskExecutor and TaskScheduler Implementations

Spring defines two core interfaces: TaskExecutor for async execution and TaskScheduler for scheduled execution. Common TaskExecutor implementations include:

SyncTaskExecutor – synchronous execution (mainly for testing).

SimpleAsyncTaskExecutor – creates a new thread per task, supports concurrency.

ConcurrentTaskExecutor – rarely used directly.

ThreadPoolTaskExecutor – most common; exposes ThreadPoolExecutor properties for bean‑based configuration.

Example bean configuration:

@Bean
public SimpleAsyncTaskExecutor simpleAsyncTaskExecutor() {
    SimpleAsyncTaskExecutor executor = new SimpleAsyncTaskExecutor();
    executor.setThreadNamePrefix("async-pack-");
    return executor;
}

For scheduling, TaskScheduler implementations such as ThreadPoolTaskScheduler or ScheduledExecutorService can be customized:

@Bean
public ThreadPoolTaskScheduler threadPoolTaskScheduler() {
    ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
    scheduler.setPoolSize(2);
    scheduler.setThreadNamePrefix("scheduler-pack-");
    return scheduler;
}

4. New Features in Spring 6.1

Starting with Spring 6.1, both ThreadPoolTaskExecutor and ThreadPoolTaskScheduler support pause/resume and graceful shutdown via the Spring lifecycle. Additionally, SimpleAsyncTaskExecutor and SimpleAsyncTaskScheduler introduce a virtualThreads option that aligns with JDK 21 virtual threads, providing lightweight concurrency and graceful shutdown.

5. Practical Example

5.1 Asynchronous Task Control

@Bean
public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
    ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
    executor.setCorePoolSize(5);
    executor.setMaxPoolSize(5);
    executor.setQueueCapacity(20);
    return executor;
}

@Resource
private ThreadPoolTaskExecutor threadPoolTaskExecutor;

@Async
public void async1() {
    System.err.printf("%s, async task async1 executing...%n", Thread.currentThread().getName());
}

public void stop() {
    this.threadPoolTaskExecutor.stop(() -> System.err.println("Async task stopped..."));
}

public void start() {
    this.threadPoolTaskExecutor.start();
}

Calling /stop pauses new async tasks; /start resumes them. Existing running tasks continue until completion.

Async task execution output
Async task execution output

5.2 Scheduled Task Control

@Bean
public ThreadPoolTaskScheduler threadPoolTaskScheduler() {
    ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
    scheduler.setPoolSize(5);
    scheduler.setThreadNamePrefix("scheduler-pack-");
    return scheduler;
}

@Resource
private ThreadPoolTaskScheduler threadPoolTaskScheduler;

@Scheduled(fixedRate = 3000)
public void scheduler() {
    System.err.printf("%s, scheduled task executing...%n", Thread.currentThread().getName());
}

public void stop() {
    this.threadPoolTaskScheduler.stop(() -> System.err.println("Scheduled task stopped..."));
}

public void start() {
    this.threadPoolTaskScheduler.start();
}

Stopping the scheduler pauses future executions; starting it resumes. Missed executions during the pause are executed once when resumed.

Scheduled task output
Scheduled task output

6. Graceful Shutdown

Both async and scheduled executors provide a shutdown method:

ThreadPoolTaskExecutor#initiateShutdown();
ThreadPoolTaskScheduler#initiateShutdown();

Invoking these methods triggers a graceful termination by calling the underlying thread pool’s shutdown() method.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Spring BootScheduled TasksThreadPoolTaskExecutorAsyncThreadPoolTaskSchedulerSpring 6.1
Spring Full-Stack Practical Cases
Written by

Spring Full-Stack Practical Cases

Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.