동기와 비동기, Spring의 @Async에 대하여

na.ram·2025년 5월 7일

Spring

목록 보기
8/13
post-thumbnail

🔎 동기와 비동기?

용어 정리

caller :: 호출하는 함수
callee :: 호출당하는 함수

동기

caller가 callee에게서 응답이 돌아올 때까지 대기합니다.

  • 장점
    • 간단한 설계
    • 직관적
  • 단점
    • 요청에 대한 결과가 반환되기 전까지 대기해야 함

비동기

caller가 callee의 응답에 관심이 없기 때문에 호출 후, 대기하지 않습니다.

  • 장점
    • 요청에 대한 결과가 반환되기를 기다리지 않고, 다른 작업을 수행할 수 있어 자원을 효율적으로 사용
  • 단점
    • 동기 방식보다 복잡한 설계

🔎 Spring에서의 비동기 구현?

Application 클래스에 @EnableAsync 어노테이션을 적용하고, 비동기 처리를 사용하고자 하는 메서드에 @Async 어노테이션을 붙여 사용합니다.
그러나 이 경우에는 Thread Executor로 SimpleAsyncTaskExecutor를 사용하게 되는데, SimpleAsyncTaskExecutor는 비동기 작업마다 새로운 쓰레드를 생성하기 때문에 잘 사용하지 않습니다.

대신 AsyncConfig를 직접 정의하고, 메서드에 @Async 어노테이션을 붙여 사용합니다.

주의점

@Async 어노테이션을 붙인 메서드는 public 접근 제어자를 사용해야 하며, self-invocation(같은 클래스 내부에서 메서드 직접 호출)이 불가능합니다.


@Async 어노테이션이 붙은 메서드들은 void, Future, ListenableFuture, CompletableFuture 중 하나의 반환 타입을 가져야 합니다.

반환 타입을 Future, ListenableFuture, CompletableFuture로 두는 경우에는 return 값을 받을 수 있습니다.

Future

Future는 blocking 방식으로 동작하기 때문에 비동기 처리 시에 잘 사용하지 않습니다.
.isDone() 메서드를 통해 완료 여부를 boolean 값으로 확인 가능하고, .get()을 통해 결과를 가져올 수 있습니다.

ListenableFuture

ListenableFuture는 콜백을 통해 non-blocking 처리가 가능합니다.
addCallback() 메서드의 첫 번째 파라미터는 성공 시에 실행할 로직, 두 번째 파라미터는 실패 시에 실행할 로직을 지정해주면 됩니다.

CompletableFuture

CompletableFuture는 콜백을 통해 non-blocking 처리가 가능하며, 여러 비동기 작업을 조합하거나 체이닝할 수 있습니다.

Blocking Vs. Non-Blocking

Blocking은 callee가 작업을 마칠 때까지 caller의 작업이 Blocking 됩니다. (제어권callee가 가짐)
Non-Blocking은 callee의 작업과 상관없이 caller가 작업을 수행합니다. (제어권caller가 가짐)


예제 코드

비동기 메서드와 반환 타입을 CompletableFuture로 두는 예제 코드입니다.

회원가입 메서드는 로직 끝에 회원가입 쿠폰을 발급 메서드를 호출합니다.


쿠폰 발급 메서드는 회원가입 쿠폰을 저장해야 하지만 일부러 예외를 던지도록 했습니다.


회원가입 메서드에서 쿠폰 발급에 실패할 시의 동작을 정해뒀기 때문에 실패 로그가 남았습니다.

0개의 댓글