@Async

박종원·2025년 3월 2일

개요

이전 글에서는 CompleteFuture에 관한 비동기 처리를 작성하였습니다.
이번 글에서는 @Async를 통한 비동기 처리에서 알아보겠습니다.

@Async 기본 개념

@Async 어노테이션은 Spring Framework에서 제공하는 기능으로, 메소드를 비동기적으로 실행할 수 있게 해줍니다. 이 어노테이션이 적용된 메소드는 호출 시 별도의 스레드에서 실행되며, 호출자는 메소드의 실행 완료를 기다리지 않고 즉시 다음 작업을 진행할 수 있습니다.
비동기 처리의 주요 이점

응답성 향상: 시간이 오래 걸리는 작업을 백그라운드로 넘겨 사용자 인터페이스의 응답성을 유지할 수 있습니다.
처리량 증가: 여러 작업을 병렬로 처리하여 전체 시스템 처리량을 향상시킬 수 있습니다.
리소스 활용도 개선: CPU 및 I/O 작업을 더 효율적으로 활용할 수 있습니다.

Spring Boot에서 @Async 설정하기

Spring Boot에서 @Async를 사용하려면 몇 가지 설정이 필요합니다.

  1. @EnableAsync 활성화
    애플리케이션 클래스 또는 구성 클래스에 @EnableAsync 어노테이션을 추가하여 비동기 처리 기능을 활성화합니다.
    javaCopy@SpringBootApplication
    @EnableAsync
    public class MyApplication {
    public static void main(String[] args) {
    SpringApplication.run(MyApplication.class, args);
    }
    }
  2. 기본 스레드 풀 사용하기
    별도의 구성 없이 @Async를 사용하면 Spring은 기본 SimpleAsyncTaskExecutor를 사용합니다. 이 executor는 매 요청마다 새로운 스레드를 생성합니다.
  3. 커스텀 Executor 설정하기
    실제 프로덕션 환경에서는 스레드 풀을 커스터마이징하는 것이 좋습니다.
@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {

    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(5);
        executor.setMaxPoolSize(10);
        executor.setQueueCapacity(25);
        executor.setThreadNamePrefix("MyAsync-");
        executor.initialize();
        return executor;
    }
    
    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return new SimpleAsyncUncaughtExceptionHandler();
    }
}

비동기 메소드 구현하기

@Async 어노테이션을 사용하여 비동기 메소드를 구현하는 방법을 알아보겠습니다.
기본 비동기 메소드

@Service
public class EmailService {

    @Async
    public void sendNotificationEmail(String email) {
        // 이메일 전송 로직 (시간이 오래 걸릴 수 있는 작업)
        System.out.println("Sending email to: " + email);
        try {
            // 이메일 전송 시뮬레이션
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        System.out.println("Email sent to: " + email + " in thread: " + Thread.currentThread().getName());
    }
}

위 메소드를 호출하면 즉시 제어권이 반환되고, 이메일 전송은 백그라운드에서 계속 진행됩니다.
여러 스레드 풀 사용하기
여러 유형의 비동기 작업에 대해 서로 다른 스레드 풀을 사용할 수 있습니다.

Configuration
@EnableAsync
public class AsyncConfig {

    @Bean(name = "emailExecutor")
    public Executor emailExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(2);
        executor.setMaxPoolSize(5);
        executor.setQueueCapacity(10);
        executor.setThreadNamePrefix("Email-");
        executor.initialize();
        return executor;
    }
    
    @Bean(name = "reportExecutor")
    public Executor reportExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(3);
        executor.setMaxPoolSize(8);
        executor.setQueueCapacity(20);
        executor.setThreadNamePrefix("Report-");
        executor.initialize();
        return executor;
    }
}

특정 executor를 지정하여 사용:

@Service
public class AsyncService {

    @Async("emailExecutor")
    public void processEmails() {
        // 이메일 처리 로직
    }
    
    @Async("reportExecutor")
    public void generateReports() {
        // 보고서 생성 로직
    }
}

0개의 댓글