Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
241 changes: 241 additions & 0 deletions 7주차/4. Blocking vs Non-blocking & Synchronous vs Asynchronous.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
# 4. Blocking vs Non-blocking & Synchronous vs Asynchronous

**Blocking**, **Non-blocking**, **Synchronous**, **Asynchronous**.

비슷해 보이지만 **다른 개념**이며, I/O 처리, 네트워크 통신, 시스템 프로그래밍 등에서 자주 등장합니다.

---

![image](https://github.com/user-attachments/assets/36a30d33-92ae-4fda-97b0-af73e625c3a6)


## 🍤 용어 정리

| 구분 | 의미 | 주체 | 비유 |
| --- | --- | --- | --- |
| **Blocking** | 요청한 작업이 끝날 때까지 **현재 스레드가 대기** | 호출자 (Thread) | "창구 앞에서 기다림" |
| **Non-blocking** | 요청하자마자 **바로 리턴**, 다른 일 가능 | 호출자 (Thread) | "번호표 받고 돌아다님" |
| **Synchronous** | **작업 결과를 직접 확인**해야 다음 진행 | 제어 흐름 (코드 레벨) | "일일이 확인하며 작업" |
| **Asynchronous** | 결과는 **콜백 등으로 나중에 통보**, 바로 다음 코드 실행 | 제어 흐름 (코드 레벨) | "작업 지시 후 다른 일 먼저" |

<br>

---

<br>

## 🛑 1️⃣ Blocking이란?

> 호출한 함수가 결과를 호출된 함수에게 받 때까지 제어권을 넘겨주고 기다림
>
- 대표 예: `read()`, `accept()` 등 전통적 I/O API
- CPU가 스레드를 멈추고 **기다리기만 하므로 비효율**

```java
InputStream in = socket.getInputStream();
int data = in.read(); // 이 줄에서 블로킹! 데이터 올 때까지 대기

```

🐙 "Blocking은 스레드 점유 -> 병렬성 저하"

### 🙋‍♂️ Blocking을 쓰는 경우?

- 별다른 설정 없이 대부분의 I/O 함수는 기본적으로 Blocking 방식입니다.
- **Java의 Socket, FileInputStream, Scanner 등 대부분의 전통 API는 Blocking** 방식입니다.
- `read()`, `accept()`, `connect()` 등
- **동시 요청 수가 적거나 처리 순서를 보장해야 할 때**, 오히려 Blocking이 직관적이고 안정적인 선택일 수 있습니다.

📌 Blocking 코드를 효율적으로 쓰기 위해선:

- **스레드 풀**을 이용하여 요청을 분산 처리하거나
- 특정 작업에 대한 **타임아웃 설정**을 활용하는 것이 중요합니다.

<br>

---

<br>


## 🍟 2️⃣ Non-blocking이란?

> 함수 호출 시 즉시 리턴, 데이터가 준비 안 되어도 제어권 유지
>
- 예: Java NIO, select/poll 기반
- 스레드는 **다른 작업을 계속 수행 가능**
- configureBlocking(false)를 설정하면, read()는 데이터가 안 와도 기다리지 않음

즉시 리턴되는데, 데이터가 없으면 bytesRead == 0 또는 -1


```java
SocketChannel channel = SocketChannel.open();
channel.configureBlocking(false); // 논블로킹 설정
int bytesRead = channel.read(buffer); // 준비 안 되어 있으면 -1 또는 0 반환

```

🍤 고성능 서버, 이벤트 기반 아키텍처에 적합

### 🙋‍♂️Non-blocking을 쓰려면?

- 계속 read() 호출해서 데이터 있는지 확인하거나(제어 흐름이 결과를 직접 확인=**Synchronous**),
- Selector 같은 이벤트 감지기(나중에 이벤트 발생시 자동호출=**Asynchronous**)와 함께 써야 효율적입니다.

```java
while (true) {
int bytesRead = channel.read(buffer);

// 계속 확인 = polling
if (bytesRead > 0) { //준비된 상태
System.out.println("데이터 읽음!");
} else {
// 데이터 아직 없음 → 다른 일 하거나 다시 시도
}
}

```

<br>


---

<br>


![image](https://github.com/user-attachments/assets/db16d883-5a68-4be3-ba5e-b7a467c03f75)


## 🧶 3️⃣ Synchronous란?

> 함수 호출 → 결과 반환 → 다음 코드 실행 (순차적 흐름)
>
- 익숙한 코드 흐름, 직관적
- 단점: 느린 작업이 전체 흐름을 멈춤

```java
String result = syncApi.call(); // 결과 기다림
System.out.println(result); // 결과 이후 실행( ← 결과 없으면 실행 안 됨)

```

<br>


---

<br>


## 🌶 4️⃣ Asynchronous란?

> 결과는 콜백/이벤트리스너 등으로 나중에 받고, 먼저 다음 작업 실행
>
- 예: Java CompletableFuture, JS의 Promise, async/await
- 콜백 : 함수가 작업을 던져놓고 다음 코드로 넘어가지만,

작업이 끝났을 때 실행할 함수(=콜백)를 미리 등록해두어 나중에 결과를 받을 수 있는것


```java
CompletableFuture.supplyAsync(() -> {
return slowTask();
}).thenAccept(result -> {
System.out.println("콜백으로 결과 도착: " + result);
});
System.out.println("바로 다음 코드 실행!");

```

실제 출력 결과

```
바로 다음 코드 실행!
콜백으로 결과 도착: (slowTask의 결과)

```

🧨 비동기 처리: 네트워크 요청, 디스크 I/O에 매우 효율적

<br>


---

<br>


## 👊구분

*Blocking/Non-blocking: 스레드가 멈추냐 안 멈추냐*

*Synchronous/Asynchronous: 코드 실행이 결과를 기다리냐, 콜백으로 처리하냐*

| 구분 | 초점 | 스레드 멈춤 여부 | 설명 |
| --- | --- | --- | --- |
| **Blocking / Non-blocking** | **스레드의 상태** | ✅ 관련 있음 | 함수 호출 시 스레드가 멈추느냐 바로 리턴되느냐 |
| **Synchronous / Asynchronous** | **제어 흐름의 구조** | ❌ 직접 관련 없음 | 코드를 순차적으로 실행하느냐, 콜백/이벤트로 처리하느냐 |

<br>


---

<br>


## 🐡 조합별 정리

| 조합 | 특징 |
| --- | --- |
| **Synchronous + Blocking** | 호출한 함수가 결과를 받을 때까지 멈추고 대기. 전통적인 방식. |
| **Synchronous + Non-blocking** | 결과를 직접 확인하지만, 함수는 바로 제어권을 반환. 계속 polling 등 필요. |
| **Asynchronous + Blocking** | 결과는 나중에 받지만, 그 결과를 받기 전까지 스레드는 멈추고 기다림. 비동기로 던져도 의미가 없어 비효율적. 현실에선 거의 쓰이지 않음. |
| **Asynchronous + Non-blocking** | **가장 효율적!** 결과는 나중에 콜백/이벤트로 받고, 호출 직후 다른 작업 가능. |

### 🎯 Synchronous + Non-blocking vs Synchronous + Blocking

| 항목 | Synchronous + Blocking | Synchronous + Non-blocking |
| --- | --- | --- |
| ✅ 코드 흐름 | 순차적이며 직관적 | 순차적이지만 polling 필요 |
| ✅ 스레드 점유 | 요청마다 스레드가 멈춤 | 스레드는 계속 작동 가능 |
| ✅ 효율성 | 단순하지만 동시성 낮음 | 스레드 낭비는 적지만 관리 복잡 |
| ✅ 적합한 상황 | 로직이 단순하고 I/O 양 적은 환경(ex. CLI 유틸, 테스트 코드) | 빠르게 반복적으로 결과를 확인해야 하는 상황(ex. 파일 상태 반복 체크 등) |

💬 결론: Non-blocking이 효율적일 수 있지만, 코드 복잡도가 올라가고 polling이 필요한 경우 **Synchronous + Blocking이 오히려 더 단순하고 안정적**일 수 있음.

<br>


---

<br>


## 🧃 팁

- 🍤 서버 개발: 대규모 동시성 처리 → Non-blocking + Asynchronous 조합 권장
- 🍜 로직 간 의존도 높음: Synchronous가 관리 쉬움
- 🌶 빠른 응답 필요: Asynchronous 방식 추천 (이벤트 루프 기반)

**추가자료 :**

- https://velog.io/@akfls221/%EB%8F%99%EA%B8%B0%EB%B9%84%EB%8F%99%EA%B8%B0-NonBlocking-Blocking%EA%B3%BC-%EC%9B%B9-%EC%84%9C%EB%B2%84%EC%9D%98-%EA%B4%80%EA%B3%84

**Spring MVC**는 기본적으로 **블로킹 구조**지만, 대부분의 웹 서비스에서는 무리 없이 작동
동시성 최적화나 대규모 트래픽 처리가 필요하다면 Spring WebFlux처럼 논블로킹 프레임워크가 적합

<br>


---

<br>


## 🐙 참고자료

- https://homoefficio.github.io/2017/02/19/Blocking-NonBlocking-Synchronous-Asynchronous/?utm_source=chatgpt.com
- https://github.com/gyoogle/tech-interview-for-developer/blob/master/Computer%20Science/Network/%5BNetwork%5D%20Blocking%2CNon-blocking%20%26%20Synchronous%2CAsynchronous.md#network-blockingnon-blocking--synchronousasynchronous