Async Programming in Spring Boot with @Async

When you’re building responsive applications, especially REST APIs, blocking operations can slow down performance. Imagine sending emails, logging audit trails, or fetching third-party data — you don’t want your main thread to wait.

That’s where Spring Boot @Async programming comes in!

Using the @Async annotation, you can run methods asynchronously in a background thread, freeing up your main process and improving responsiveness.

In this guide, we’ll cover:

  • How to enable and use @Async
  • Return types like void, Future, and CompletableFuture
  • Exception handling
  • Real-world scenarios
Async Programming in Spring Boot with @Async

✅ Step 1: Enable Async Support

To use @Async, annotate your configuration class or main class with @EnableAsync.


package com.kscodes.springboot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;

@SpringBootApplication
@EnableAsync
public class AsyncApp {
    public static void main(String[] args) {
        SpringApplication.run(AsyncApp.class, args);
    }
}

✏️ Step 2: Add a Method with @Async


package com.kscodes.springboot.service;

import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

@Service
public class EmailService {

    @Async
    public void sendEmail(String to, String content) {
        try {
            Thread.sleep(3000); // simulate delay
            System.out.println("📧 Email sent to " + to);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
}

🚀 Step 3: Call the Async Method


package com.kscodes.springboot.controller;

import com.kscodes.springboot.service.EmailService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/notify")
public class NotificationController {

    @Autowired
    private EmailService emailService;

    @PostMapping("/send")
    public String sendNotification(@RequestParam String email) {
        emailService.sendEmail(email, "Welcome!");
        return "🟢 Request received. Email is being sent in the background.";
    }
}

Even though the email takes 3 seconds to send, the response is instant because it’s handled in a separate thread.

⏳ Async Return Types

void

Best for fire-and-forget operations.

🧵 Future<T> and CompletableFuture<T>

Let you track the result later.


@Async
public CompletableFuture fetchData() {
    return CompletableFuture.completedFuture("Data Ready!");
}

Use .get() or .thenApply() to retrieve the value:


CompletableFuture result = service.fetchData();
System.out.println("Response: " + result.get());

⚠️ Exception Handling in @Async Methods

You must handle exceptions manually for void methods. For CompletableFuture, you can use .exceptionally():


@Async
public CompletableFuture riskyTask() {
    throw new RuntimeException("Boom!");
}


riskyTask()
  .exceptionally(ex -> {
      System.err.println("❌ Exception: " + ex.getMessage());
      return "Fallback";
  });

⚙️ Step 4: Custom Executor (Optional)

You can define your own thread pool:


@Configuration
public class AsyncConfig {

    @Bean(name = "taskExecutor")
    public Executor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(2);
        executor.setMaxPoolSize(4);
        executor.setQueueCapacity(500);
        executor.setThreadNamePrefix("Async-Thread-");
        executor.initialize();
        return executor;
    }
}

Then use:


@Async("taskExecutor")
public void processHeavyTask() {
    // heavy logic
}

🧠 Real-World Use Cases

Use CaseDescription
Sending EmailsBackground email dispatch after registration
LoggingSave logs/audits without blocking flow
API CallsCall external APIs concurrently
File ProcessingParse large files without freezing UI
Notification SystemsPush messages without delay

✅ Summary

Async Programming in Spring Boot is a powerful technique to boost application responsiveness and handle non-blocking operations. Whether it’s email notifications or third-party integrations, offloading them to background threads keeps your app fast and scalable.

In this tutorial, you learned:

  • How to enable and use @Async
  • Difference between void, Future, CompletableFuture
  • Exception handling for async tasks
  • How to use a custom executor

Use Async Programming in Spring Boot wisely to improve performance, especially for microservices and REST APIs.

🔗 References