동기/비동기와 블로킹/논블로킹은 표현 형태는 비슷해보여도 서로 다른 차원에서 작업의 수행 방식을 설명하는 개념이다.
동기/비동기는 요청한 작업에 대해 완료 여부를 신경 써서 작업을 순차적으로 수행할지 아닌지에 대한 관점이고, 블로킹/논블록킹은 단어 그대로 현재 작업이 block(차단, 대기) 되느냐 아니냐에 따라 다른 작업을 수행할 수 있는지에 대한 관점이다.

동기(Synchronous)는 요청한 작업에 대해 완료 여부를 따져 순차대로 처리하는 것을 뜻하며, 비동기(Asynchronous)는 동기와 반대로 요청한 작업에 대해 완료 여부를 따지지 않고 자신의 다음 작업을 수행하는 것을 뜻한다.

작업을 순차적으로 처리하고, 이전 작업으로 끝나야 다음 작업이 실행되는 방식
System.out.println("1번 작업 시작");
Thread.sleep(2000); // 2초 대기
System.out.println("2번 작업 완료");
작업을 병렬적으로 처리할 수 있고, 어떤 작업이 끝날 때까지 기다리지 않고 다음 작업을 진행하는 방식
System.out.println("1번 작업 시작");
new Thread(() -> {
try {
Thread.sleep(2000);
System.out.println("2번 작업 완료");
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
System.out.println("메인 스레드 종료");
| 구분 | 동기(Sync) | 비동기(Async) |
|---|---|---|
| 처리 방식 | 요청 → 응답을 받을 때까지 기다림 | 요청 → 응답을 기다리지 않고 바로 다음 실행 |
| 흐름 제어 | 순차적 | 병렬적, 분기 처리 |
| 장점 | 구현이 단순함 | 자원 활용이 효율적, 높은 성능 가능 |
| 단점 | 느림, 자원 낭비 가능 | 복잡한 흐름 제어 필요 |
블로킹과 논블로킹은 단어에서 알 수 있듯이 다른 요청의 작업을 처리하기 위해 현재 작업을 block(차단, 대기) 하냐 안하냐의 유무를 나타내는 프로세스의 실행 방식이다.
블로킹은 자신의 작업을 진행하다가 다른 주체의 작업이 시작되면 다른 작업이 끝날 때까지 기다렸다가 자신의 작업을 시작하는 것이고, 논블로킹은 다른 주체의 작업에 관련없이 자신의 작업을 하는 것이다.

자신의 작업을 진행하다가, 다른 작업을 호출했을 때 제어권이 넘어가서 다른 작업이 끝나고 제어권이 돌아오면 작업을 시작하는 것이다.
요청에 대한 결과가 처리될 때까지 결과를 기다리고, 결과가 돌아올 때까지 자신의 작업을 수행할 수 없다.

1. A함수가 B함수를 호출하면 B에게 제어권을 넘김
2. 제어권을 넘겨받은 B는 함수를 실행하고, A는 B에게 제어권을 넘겼기 때문에 함수 실행을 잠시 멈춤(block)
3. B함수는 실행이 끝나면 자신을 호출한 A에게 제어권을 돌려줌
➡️피호출자로부터 호출자에게 제어권이 돌아오면 작업을 다시 시작할 수 있다.
자신의 작업을 진행하다가 다른 작업을 호출하더라도 제어권은 호출자가 가지고 있어 기존 작업을 계속 수행할 수 있다.
피 호출자는 멀티스레드나 콜백함수를 이용해 작업을 각각의 스레드가 제어권을 가지고 따로 수행한다.
논블로킹 방식에서는 결과값을 바로 사용할 수 없기 때문에, 비동기(Asynchronous) 방식과 결합하여 작업이 완료될 때 호출되는 콜백 함수(callback function)를 이용하여 결과값을 처리하며, 콜백 함수는 비동기 함수가 완료된 후 자동으로 호출되는 함수이다.

➡️블로킹과 마찬가지로 호출할 때 제어권을 넘겨주기는 하지만 바로 돌려받으며, 제어권을 바로 돌려받기 때문에 계속해서 다른 작업을 할 수 있다
| 구분 | 블로킹 I/O | 논블로킹 I/O |
|---|---|---|
| 제어권 반환 | 작업 완료 후 | 바로 반환 |
| 대기 여부 | 해당 스레드가 작업 끝날 때까지 대기 | 대기하지 않음 |
| 효율성 | 낮음 (스레드 수 증가) | 높음 (스레드 수 최소화 가능) |
| 구현 난이도 | 낮음 | 높음 (이벤트 처리 또는 리액티브 필요) |
제어권이 넘어가며, 순서대로 진행된다.

➡️두 개의 작업이 시작과 동시에 끝나는 시간이 일치한다(Sync)
한쪽에서 작업이 시작되면 한쪽에서는 작업을 멈추고 기다린다(Blocking)
애플리케이션이 DB 쿼리를 날리고 쿼리 결과를 받는다면 이것은 동기 블로킹이 된다.
제어권이 넘어가진 않지만, 순서대로 진행되어야 하기 때문에 계속적으로 작업 완료를 확인한다.

➡️두 개 이상의 작업이 시작 시간이나 끝나는 시간이 같아야 하며(Sync) 다른 작업을 기다리지 않는다.(NonBlocking) 결국에는 제어권을 잃지 않아도 다른 작업이 끝날때까지는 현재 작업을 마칠 수가 없다.
순서대로 진행되지 않아도 되지만 제어권이 넘어갔기 떄문에 호출자는 더 진행하지 못하므로 대기시간 발생

➡️다른 작업의 작업 마침여부를 기다리지는 않지만 결국엔 제어권이 작업중인 쪽에 넘어가 있기 때문에 동기-블로킹과 비슷하게 동작한다.
Sync-Blocking과 비교했을 때 이점이 없기 때문에 거의 사용되지 않는다.
제어권이 넘어가진 않았지만, 순서대로 진행되지 않아도 되기 때문에 호출하고 작업을 하고 있다가 완료시 콜백한다.

➡️함수가 다른 함수를 호출할 때 제어권을 주지 않고 자신의 코드를 계속 실행한다.
함수가 다른 함수를 호출할 때 콜백함수를 함께 줘서 다른 함수는 자신의 작업을 처리하면 콜백 함수를 실행한다.