시작하기에 앞서
Block과Non-block,sync와async 개념을 이해하기 위해서는 다음의 두 용어를 짚고 넘어가야 합니다.
- 제어권
- 자신(함수)의 코드를 실행할 권리 같은 것입니다.
- 제어권을 가진 함수는 자신의 코드를 끝까지 실행한 후, 자신을 호출한 함수에게 돌려줍니다.
- 결과값을 기다린다는 것
- A함수에서 B함수를 호출했을 때, A함수가 B함수의 결과값을 기다리는 지의 여부를 의미합니다.
Blocking과 Non-Blocking
Blocking과 Non-blocking은 A함수가 B함수를 호출했을 때, 제어권을 어떻게 처리하느냐에 따라 달라집니다.
Blocking
블로킹은 A함수가 B함수를 호출하면, 제어권을 A가 호출한 B함수에게 넘겨주는 것을 의미합니다.

- A함수가 B함수를 호출하면서 B에게 제어권을 넘겨줍니다.
- 제어권을 넘겨받은 B는 자신을 실행합니다. 이때 A는 B에게 제어권을 넘겨주었기 때문에 함수 실행을 잠시 멈춥니다.
- B함수는 실행이 끝나면 자신을 호출한 A에게 제어권을 돌려줍니다.
Non-Blocking
논블로킹은 A함수가 B함수를 호출해도 제어권은 그대로 자신이 가지고 있습니다.

- A함수가 B함수를 호출하면, B함수는 실행되지만, 제어권은 A함수가 그대로 가지고 있습니다.(A함수가 B함수를 호출하는 순간에만 B함수가 제어권을 가지거 자신을 실행시킨 후 거의 즉시 자신을 호출한 A함수에게 제어권을 돌려주는 방식)
- A함수는 계속 제어권을 가지고 있기 때문에 B함수를 호출한 이후에도 자신의 코드를 계속 실행합니다.
Synchronous와 Asynchronous
동기와 비동기의 차이는 호출되는 함수의 작업 완료 여부를 신경쓰는 지 여부의 차이입니다.
Synchronous
함수A가 함수B를 호출한 뒤, 함수B의 리턴값을 계속 확인하면서 신경쓰는 것이 동기입니다.
Asynchronous
함수A가 함수B를 호출할 때 콜백 함수를 함께 전달해서, 함수 B의 작업이 완료되면 함께 보낸 콜백 함수를 실행합니다.
함수A는 함수B를 호출한 후로 함수 B의 작업 완료 여부에는 신경을 쓰지 않습니다.
블로킹과 논블로킹, 동기와 비동기 비교
Sync-Blocking
동기를 블로킹처럼 실행하는 것은 이해하기 쉽습니다.

함수 A는 함수 B의 리턴값을 필요로 합니다(동기). 그래서 제어권을 함수 B에게 넘겨주고, 함수 B가 실행을 완료하여 리턴값과 제어권을 돌려줄 때까지 기다립니다.(블로킹)
Sync-NonBlocking
동기를 논블로킹처럼 동작시킬 수 있습니다.

A함수는 B함수를 호출합니다. 이때 A함수는 B함수에게 제어권을 주지 않고, 계속해서 자신의 코드를 실행합니다.(논블로킹).
그런데 A함수는 B함수의 리턴값이 필요하기 때문에, 중간중간 B함수에게 함수 실행을 완료했는 지 물어봅니다(동기)
즉, 논블로킹인 동시에 동기인 것입니다.
해당 방법은 리그오브레전드의 게임 진입 전 유저들의 상태를 체크하는 방식으로도 활용됩니다.
Async-NonBlocking
비동기 논블로킹은 이해하기 쉽습니다.

이때 제어권을 B함수에게 주지 않고, 자신이 계속 가지고 있으므로(논블로킹) B함수를 호출한 이후에도 멈추지 않고 자신의 코드를 계속 실행합니다.
그리고 B함수를 호출할 때 콜백함수를 함께 줍니다. B함수는 자신의 작업이 끝나면 A함수가 준 콜백함수를 실행합니다(비동기).
Async-blocking
비동기 블로킹은 사실 마주하기 쉽지 않습니다. 개발 과정에서 발생하는 오류의 유형이라고도 합니다.

A함수는 B함수의 리턴값에 신경쓰지 않고, 콜백함수를 보냅니다.(비동기)
그런데, B함수의 작업에 관심이 없음에도 불구하고, A함수는 B함수에게 제어권을 넘깁니다.(블로킹)
따라서, A함수는 자신과 관련 없는 B함수의 작업이 끝날 때까지 기다려야 합니다.
정리

스프링에서 비동기 처리는 어떻게 하며 무엇을 주의해야 하나요?
스프링에서는 @Async 어노테이션을 사용하여 비동기 처리를 수행할 수 있습니다. 해당 어노테이션을 사용하기 위해서는 몇 가지 주의할 부분이 있는데요.
기본적으로 @Async 가 적용된 메서드에서 발생하는 예외는 호출자에게 전파되지 않습니다. 비동기 메서드에서 예외를 정상적으로 처리하기 위해서는 별도의 비동기 예외 처리기를 사용해야 합니다.
또한, @Async 어노테이션은 프록시 기반으로 동작하기 때문에 같은 클래스 내부에서 직접 호출하는 경우 별도의 스레드에서 메서드가 실행되지 않습니다. 그리고, 비동기 메서드 내에서 생성한 트랜잭션은 상위 트랜잭션과 무관한 생명주기를 가집니다.
Start the conversation