본문 바로가기

SPRING

@Async 어노테이션

 

@Async 어노테이션 이란 ?

@Async 어노테이션은 스프링 프레임워크에서 비동기 처리를 위해 제공하는 어노테이션이다.

이 어노테이션을 메소드에 붙이면  스프링은 해당 메소드를 비동기적으로 실행한다.

@Async 어노테이션을 이해하기 위해서는 스프링의 AOP 와 스레드 풀의 개념을 알아야 한다.

 

스프링에서 @Async 를 사용하기 위해서는 @EnableAsync 어노테이션을 설정 클래스에 추가해야한다.

이 설정을 통해 스프링은 비동기 작업을 위한 설정을 활성화하고, AsyncTaskExecutor 인터페이스의 구현체를 사용하여 비동기 작업을 처리한다.

 

@EnableAsync 어노테이션을 통해 스프링이 비동기 처리를 위한 프록시 객체를 생성하고, 이를 통해 실제 메소드 호출을 비동기적으로 처리하기 때문이다.기본적으로 스프링은 SimpleAsyncTaskExecutor 를 사용하지만, ThreadPoolTaskExecutor와 같은 다른 Executor를 사용하여 성능을 향상시킬 수 있다.

 

SimpleAsyncTaskExecutor는 매 요청 마다 새로운 스레드를 생성하는 반면, ThreadPoolTaskExecutor는 미리 생성된 스레드 풀을 사용하기 때문에 오버헤드를 줄이고 성능을 향상시킬 수 있다.

 

스레드 풀이란?

스레드 풀은 사전에 스레드를 생성하고 관리하는 기술이다. 이를 통해 요청마다 스레드를 새로 생성하는 비용을 줄이고, 시스템 자원의 효율적인 사용을 가능하게 한다. 스프링은 ThreadPoolTaskExecutor를 통해 스레드 풀을 쉽게 구성할 수 있다.

ThreadPoolTaskExecutor는 스레드 풀의 크기, 최대 풀 크기, 큐 용량 등을 설정할 수 있다.

 

스프링에서 스레드 풀을 설정하는 방법은 application.properties 또는 @Configuration 클래스를 통해 ThreadPoolTaskExecutor 빈을 정의하고, 필요한 속성을 설정하는 것이다.

 

스레드 풀 설정 예제

 

 @Configuration
    public class AsyncConfig {
        @Bean
        public Executor taskExecutor() {
            ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        
            taskExecutor.setCorePoolSize(50);
            taskExecutor.setMaxPoolSize(500);
            taskExecutor.setQueueCapacity(0);
            taskExecutor.setThreadNamePrefix("test Executor - ");
            taskExecutor.setKeepAliveSeconds(30);
            taskExecutor.setAllowCoreThreadTimeOut(true);
            taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
            taskExecutor.setWaitForTasksToCompleteOnShutdown(true);

            taskExecutor.initialize();

            return taskExecutor;
        }
    }

 

corePoolSize 

  • 생성해서 사용할 스레드 풀에 속한 기본 스레드 갯수
  • default 값은 1

maxPoolSize

  • 최대 스레드 갯수
  • default 값은 Integer.MAX_VALUE(약 21억)

queueCapacity

  • 이벤트 대기 큐 크기
  • default 값은 Integer.MAX_VALUE(약 21억)

keepaliveseconds

  • 스레드 풀에서 유휴 상태의 스레드가 유지되는 시간

setThreadNamePrefix

  • 스레드 이름의 접두사를 설정
  • 스레드 풀에서 생성되는 각 스레드의 이름을 일관되게 관리할 수 있도록 도와준다.

rejectedExecutionHandler

  • 태스크 처리량이 스레드 갯수가 max로 채워지고 queue 대기수를 넘어서는 경우에 RejectExecutionException 이 발생
  • 해당 Exception을 다양한 방식으로 처리할수있도록 제공하는 Handler 클래스의 종류
    • AbortPolicy
      • default
        • RejectExecutionHandler 예외 발생 시킴
    • DiscardOldestPolicy
      • 오래된 작업을 skip
      • 모든 태스크가 반드시 처리될 필요가 없을때 사용
    • DiscardPolicy
      • 처리하려는 작업을 skip\
      • 모든 태스크가 반드시 처리될 필요가 없을때 사용
    • CallerRunsPolicy
      • shutdown 상태가 아니라면 요청한 Caller Thread에서 직접 처리함
      • 태스크 유실을 최소화하기 위해선 이 구현체를 사용해야함

AllowcoreThreadTimeout

  • 기본 스레드가 유휴 상태일 때 종료할지 여부를 설정하는 옵션

waitForTasksToCompleteOnShutdown

  • 애플리케이션이 종료될 때 실행 중이던 작업을 모두 완료하고 종료할지 여부를 설정하는 옵션
  • 기본값 : false -> 애플리케이션이 종료되면 실행 중이던 작업을 즉시 중단
  • true 로 설정하면 남아있는 작업을 모두 완료한 후 종료