F-LAB JAVA · 4주차 · Phase 2 · Sync/Async × Blocking/Non-Blocking 4분면
이 Unit을 끝내면 다음을 답할 수 있어야 한다.
블로킹 (Blocking) 과 논블로킹 (Non-Blocking) 은 "제어권 (control)" 을 다루는 축으로, 호출된 함수가 끝날 때까지 호출자가 제어권을 잃고 대기하는가 가 판단 기준이다.
블로킹 은 호출된 함수가 완료될 때까지 호출자가 제어권을 잃고 대기 (그 스레드는 "할 일이 없는 상태"), 논블로킹 은 호출 즉시 제어권을 반환 하여 호출자가 다른 일을 할 수 있다.
핵심 질문: "OS (또는 호출된 함수) 가 제어권을 가져갔는가, 즉시 돌려줬는가?" — 가져갔으면 블로킹, 즉시 돌려줬으면 논블로킹.
Sync (작업 순서 축) 와 Blocking (제어권 축) 은 다르다 — Sync 는 "완료 확인", Blocking 은 "제어권 대기" 이며, 동기+논블로킹 (polling) 처럼 조합이 가능하다.
논블로킹에서 결과를 받으려면 polling (반복 확인) 또는 callback (완료 통보) 을 사용한다.
블로킹:
세탁소에서 옷 세탁 끝날 때까지 기다림
- 옷 맡김 (호출)
- 세탁 끝날 때까지 서 있음 (제어권 잃음)
- 다른 일 못 함
- 완료 후 옷 받고 떠남
논블로킹:
옷 맡기고 바로 나옴
- 옷 맡김 (호출)
- 즉시 나옴 (제어권 유지)
- 다른 일 (장보기 등)
- polling: 가끔 들러서 "다 됐어요?"
- callback: 다 되면 전화 줌
핵심:
- 블로킹: 끝날 때까지 묶임 (제어권 잃음)
- 논블로킹: 바로 자유 (제어권 유지)
→ 블로킹 = 제어권 잃고 대기, 논블로킹 = 제어권 유지.
1. 블로킹의 정의
2. 논블로킹의 정의
3. 제어권의 의미
4. "제어권을 가져갔는가?"
5. Sync와 Blocking의 차이
6. 논블로킹에서 결과 받기 (polling/callback)
7. 블로킹의 스레드 상태
8. 논블로킹 I/O의 동작
9. 면접 + 자기 점검
블로킹 (Blocking):
호출된 함수가 완료될 때까지
호출자가 제어권을 잃고 대기하는 것.
핵심:
- 제어권 넘어감
- 호출자 대기
- 완료까지 멈춤
블로킹 흐름:
호출자 스레드:
1. 함수 호출
2. 제어권 함수로 넘김
3. 대기 (할 일 없음)
...
4. 함수 완료
5. 제어권 돌아옴
6. 다음 코드 진행
대기 중 = 블록됨
// 블로킹 호출
public void blockingExample() {
System.out.println("Before");
String data = blockingRead(); // ★ 완료까지 대기 (블록)
// 이 줄에서 멈춤
// 제어권 read 로
System.out.println("After: " + data); // read 완료 후
}
private String blockingRead() {
// 예: 소켓 읽기, DB 조회, 파일 읽기
// 데이터 올 때까지 대기
return socket.read(); // 데이터 없으면 계속 대기
}
블로킹 작업의 예:
1. 전통적 I/O
- InputStream.read()
- Socket.read()
- 데이터 없으면 대기
2. 동기 DB
- JDBC 쿼리
- 결과까지 대기
3. Future.get()
- 작업 완료까지 대기
4. Thread.join()
- 스레드 종료까지 대기
5. lock.lock()
- 락 획득까지 대기
블로킹의 특징:
장점:
- 단순, 직관적
- 코드 흐름 명확
- 결과 바로 사용
단점:
- 스레드 대기 (자원 낭비)
- 많은 동시 요청 시 많은 스레드
- 처리량 한계
@Service
public class ShipmentBlockingService {
// 블로킹 — 전통적 처리
public Shipment fetch(Long id) {
// DB 조회 (블록)
Shipment shipment = repository.findById(id);
// 이 줄에서 DB 응답까지 대기 (제어권 잃음)
// 외부 API (블록)
Tracking tracking = trackingApi.fetch(shipment.getBlNo());
// API 응답까지 대기
shipment.setTracking(tracking);
return shipment;
}
// 각 호출이 블로킹
// 스레드가 대기
}
블로킹의 정의는?
답:
1. 정의:
흐름:
예:
특징:
논블로킹 (Non-Blocking):
호출 즉시 제어권을 반환하여
호출자가 다른 일을 할 수 있는 것.
핵심:
- 제어권 즉시 반환
- 호출자 대기 X
- 다른 작업 가능
논블로킹 흐름:
호출자 스레드:
1. 함수 호출
2. 즉시 제어권 반환 (결과 미완성일 수도)
3. 다른 작업 진행
4. 나중에 결과 확인 (polling) 또는 통보 (callback)
대기 X = 논블록
// 논블로킹 호출
public void nonBlockingExample() {
System.out.println("Before");
// 즉시 반환 (결과 미완성 가능)
int bytesRead = nonBlockingRead(); // 데이터 없으면 0 반환 (대기 X)
if (bytesRead == 0) {
// 데이터 아직 없음, 다른 일
doOtherWork();
} else {
// 데이터 있음
process();
}
System.out.println("After"); // 즉시 진행
}
private int nonBlockingRead() {
// NIO 채널 (논블로킹 모드)
// 데이터 있으면 읽고, 없으면 0 반환 (대기 X)
return channel.read(buffer);
}
논블로킹 작업의 예:
1. NIO 채널 (논블로킹 모드)
- channel.configureBlocking(false)
- read() 가 즉시 반환 (0 가능)
2. CompletableFuture
- 즉시 Future 반환
- 콜백
3. tryLock()
- 락 시도, 실패 시 즉시 false
4. Future.isDone()
- 완료 확인 (대기 X)
5. Reactive (Flux/Mono)
- 논블로킹 스트림
논블로킹의 특징:
장점:
- 스레드 효율 (대기 X)
- 적은 스레드로 많은 작업
- 처리량 ↑
- 응답성 ↑
단점:
- 복잡 (polling/callback)
- 결과 확인 로직 필요
- 디버깅 어려움
@Service
public class ShipmentNonBlockingService {
// 논블로킹 — CompletableFuture
public CompletableFuture<Shipment> fetchAsync(Long id) {
return CompletableFuture
.supplyAsync(() -> repository.findById(id)) // 백그라운드
.thenCompose(shipment -> // 콜백 체인
fetchTrackingAsync(shipment.getBlNo())
.thenApply(tracking -> {
shipment.setTracking(tracking);
return shipment;
}));
// 호출자는 즉시 Future 반환받음 (대기 X)
}
// Reactive (WebFlux)
public Mono<Shipment> fetchReactive(Long id) {
return reactiveRepository.findById(id) // 논블로킹
.flatMap(shipment ->
trackingService.fetch(shipment.getBlNo())
.map(tracking -> {
shipment.setTracking(tracking);
return shipment;
}));
// 완전 논블로킹 체인
}
}
논블로킹의 정의는?
답:
1. 정의:
흐름:
예:
특징:
제어권 (Control):
함수의 실행 흐름을 제어할 수 있는 권리.
"지금 무엇을 실행할지 결정하는 권한."
스레드 관점:
- 제어권 있음 = 코드 실행 중
- 제어권 없음 = 다른 곳에 넘김 (대기)
제어권의 이동:
블로킹 호출:
호출자 (제어권 있음)
↓ 함수 호출
함수 (제어권 가져감)
↓ 실행 + 완료
호출자 (제어권 돌아옴)
→ 함수 실행 중 호출자는 대기
논블로킹 호출:
호출자 (제어권 있음)
↓ 함수 호출
함수 (즉시 반환)
↓
호출자 (제어권 유지)
→ 호출자가 계속 실행
제어권 잃음 = 할 일 없음:
블로킹 시:
- 제어권을 함수에 넘김
- 호출자 스레드는 "할 일 없음"
- = 블로킹 상태
- CPU 사용 X (대기)
핵심:
- 제어권 넘어감 → 대기
- 그 스레드는 놀고 있음 (블록)
제어권의 흐름:
블로킹:
호출자: ━━━┓
┃ (제어권 넘김, 대기)
함수: ┣━━━━━━┫ (실행)
┃ (제어권 반환)
호출자: ━━━┛━━━━ (계속)
↑대기 구간↑
논블로킹:
호출자: ━━━┓ ┏━━━━━━ (계속, 대기 X)
┃ 호출 ┃
함수: ┗━━━┛ (즉시 반환)
호출자 제어권 유지
제어권과 CPU 사용:
블로킹 (제어권 넘김):
- 호출자 스레드 대기
- CPU 사용 X (보통 — 진짜 블로킹)
- OS 가 다른 스레드에 CPU
- 컨텍스트 스위칭
논블로킹 (제어권 유지):
- 호출자 스레드 계속
- CPU 계속 사용
- 다른 작업 진행
public class ControlExample {
// 블로킹 — 제어권 넘김
public void blocking() {
log.info("Start");
Shipment s = repository.findById(1L); // 제어권 넘김 (대기)
// 이 스레드는 DB 응답까지 할 일 없음
log.info("Got: " + s); // 제어권 돌아온 후
}
// 논블로킹 — 제어권 유지
public void nonBlocking() {
log.info("Start");
CompletableFuture<Shipment> future =
CompletableFuture.supplyAsync(() -> repository.findById(1L));
// 즉시 반환 (제어권 유지)
log.info("Doing other work"); // 바로 실행
doOtherWork(); // DB 조회 중에도 진행
future.thenAccept(s -> log.info("Got: " + s)); // 완료 시
}
}
제어권의 의미는?
답:
1. 정의:
이동:
할 일 없음:
CPU:
Blocking/Non-Blocking 판단:
"OS (또는 호출된 함수) 가
제어권을 가져갔는가,
즉시 돌려줬는가?"
가져감 (대기) → 블로킹
즉시 돌려줌 → 논블로킹
판단:
함수 호출 시:
1. 결과 미완성이면?
- 대기 (제어권 가져감) → 블로킹
- 즉시 반환 (제어권 돌려줌) → 논블로킹
블로킹:
- 완료까지 안 돌려줌
논블로킹:
- 완료 안 됐어도 즉시 돌려줌
// 블로킹 — 제어권 가져감
int data = inputStream.read();
// 데이터 없으면 올 때까지 대기 (제어권 안 돌려줌)
// 논블로킹 — 즉시 돌려줌
channel.configureBlocking(false);
int bytesRead = channel.read(buffer);
// 데이터 없으면 0 반환 (제어권 즉시 돌려줌)
if (bytesRead == 0) {
// 데이터 없음, 다른 일
}
OS 레벨:
블로킹 시스템 콜:
- read() 시스템 콜
- 데이터 없으면 프로세스/스레드 대기 큐로
- 데이터 오면 깨움
- OS 가 제어권 관리
논블로킹 시스템 콜:
- read() with O_NONBLOCK
- 데이터 없으면 즉시 EWOULDBLOCK
- 호출자 계속
제어권 가져감 여부:
블로킹 read():
호출 → [OS: 데이터 대기...] → 데이터 → 반환
↑
제어권 OS 가 가져감 (스레드 대기)
논블로킹 read():
호출 → [OS: 데이터 확인] → 즉시 반환 (0 또는 데이터)
↑
제어권 즉시 돌려줌
public class ControlTransferExample {
// 블로킹 소켓 (제어권 가져감)
public byte[] readBlocking(Socket socket) throws IOException {
InputStream in = socket.getInputStream();
byte[] buffer = new byte[1024];
int read = in.read(buffer); // 데이터까지 대기 (제어권 가져감)
return Arrays.copyOf(buffer, read);
}
// 논블로킹 채널 (제어권 즉시)
public void readNonBlocking(SocketChannel channel) throws IOException {
channel.configureBlocking(false);
ByteBuffer buffer = ByteBuffer.allocate(1024);
int read = channel.read(buffer); // 즉시 반환 (제어권 유지)
if (read == 0) {
// 데이터 없음, 다른 일
doOtherWork();
} else if (read > 0) {
// 데이터 처리
process(buffer);
}
}
}
"제어권을 가져갔는가?" 의 의미는?
답:
1. 핵심 질문:
판단:
OS 레벨:
예:
Sync vs Blocking 한 문장:
Sync (동기) 는 "작업 완료를 확인하고 다음으로 가는가" (작업 순서) 이고,
Blocking (블로킹) 은 "호출 시 제어권을 잃고 대기하는가" (제어권) 이다.
Sync = 결과를 언제 받나
Blocking = 호출 시 대기하나
두 축:
Sync/Async:
관심: 작업 완료 통보
- 동기: 완료 확인 후 진행
- 비동기: 완료 안 기다림, 통보
Blocking/Non-Blocking:
관심: 제어권
- 블로킹: 제어권 잃고 대기
- 논블로킹: 제어권 유지
핵심:
- 작업 순서 vs 제어권
- 독립적 축
오해:
"동기 = 블로킹"
"비동기 = 논블로킹"
진실:
- 보통 함께 가지만
- 항상 X
- 4가지 조합 가능
예:
- 동기 + 논블로킹 (polling)
- 비동기 + 블로킹 (Future.get)
// 동기 + 논블로킹 (polling)
public String syncNonBlocking() {
// 논블로킹 (제어권 즉시)
while (true) {
int data = channel.read(buffer); // 논블로킹 (즉시 반환)
if (data > 0) {
return process(buffer); // 동기 (결과 확인 후 반환)
}
// 데이터 없으면 다시 시도 (polling)
// 제어권 유지 (논블로킹)
// 하지만 결과 확인하며 진행 (동기적)
}
}
// 논블로킹 (제어권 유지) + 동기 (결과 확인)
// 비동기 + 블로킹 (Future.get)
public Shipment asyncBlocking() throws Exception {
// 비동기 (작업 백그라운드)
Future<Shipment> future = executor.submit(() -> repository.findById(1L));
// 블로킹 (결과 받을 때 대기)
return future.get(); // ★ 여기서 블록 (제어권 잃음)
}
// 작업은 비동기, 결과 회수는 블로킹
| 구분 | Sync/Async | Blocking/Non-Blocking |
|---|---|---|
| 축 | 작업 순서/통보 | 제어권 |
| 질문 | 완료 확인? | 대기하나? |
| 동기/블로킹 | 완료 확인 후 | 대기 |
| 비동기/논블로킹 | 통보 | 즉시 반환 |
public class SyncBlockingDistinction {
// 동기 + 블로킹 (전통)
public Shipment syncBlocking(Long id) {
return repository.findById(id);
// 결과 확인 (동기) + 대기 (블로킹)
}
// 동기 + 논블로킹 (polling)
public Shipment syncNonBlocking(Future<Shipment> future) throws Exception {
while (!future.isDone()) { // 논블로킹 확인 (제어권 유지)
doOtherWork(); // 다른 일
}
return future.get(); // 완료됨 (동기적 결과)
}
// 비동기 + 블로킹 (Future.get)
public Shipment asyncBlocking(Long id) throws Exception {
Future<Shipment> future = executor.submit(() -> repository.findById(id));
return future.get(); // 비동기 작업, 블로킹 회수
}
// 비동기 + 논블로킹 (CompletableFuture)
public CompletableFuture<Shipment> asyncNonBlocking(Long id) {
return CompletableFuture.supplyAsync(() -> repository.findById(id));
// 비동기 + 콜백 (논블로킹)
}
}
Sync와 Blocking의 차이는?
답:
1. 한 문장:
다른 축:
오해:
조합 예:
논블로킹 결과 받기:
1. Polling (폴링)
- 주기적으로 완료 확인
- "다 됐니?" 반복
2. Callback (콜백)
- 완료 시 통보
- "다 되면 알려줘"
// Polling — 반복 확인
public Shipment pollingResult() throws Exception {
Future<Shipment> future = executor.submit(() -> repository.findById(1L));
while (!future.isDone()) { // 완료 확인 (논블로킹)
// 아직 안 됨
doSomethingElse(); // 다른 일
Thread.sleep(10); // 잠시 후 다시
}
return future.get(); // 완료됨
}
// 특징:
// - 제어권 유지 (논블로킹)
// - 반복 확인 (CPU 사용)
// - 확인 간격 조절 필요
Polling 의 트레이드오프:
너무 자주 확인:
- CPU 낭비 (바쁜 대기)
- busy waiting
너무 가끔 확인:
- 응답 지연
- 완료 후 늦게 인지
해결:
- 적절한 간격
- 또는 콜백 사용
// Callback — 완료 통보
public void callbackResult() {
CompletableFuture
.supplyAsync(() -> repository.findById(1L))
.thenAccept(shipment -> { // 완료 시 자동 호출
process(shipment);
});
// 호출자는 확인 안 함
// 완료 시 callback 자동
doOtherWork();
}
// 특징:
// - 제어권 유지 (논블로킹)
// - 반복 확인 X (효율)
// - 완료 시 통보
| 항목 | Polling | Callback |
|---|---|---|
| 확인 | 반복 (능동) | 통보 (수동) |
| CPU | 사용 (확인) | 효율 |
| 복잡도 | 단순 | 콜백 등록 |
| 응답성 | 간격에 의존 | 즉시 |
| 권장 | 드물게 | 일반적 |
// NIO Selector — 여러 채널 효율적 polling
public void selectorExample() throws IOException {
Selector selector = Selector.open();
channel.configureBlocking(false);
channel.register(selector, SelectionKey.OP_READ);
while (true) {
selector.select(); // 준비된 채널까지 대기 (효율적)
// 여러 채널 중 준비된 것만
Set<SelectionKey> keys = selector.selectedKeys();
for (SelectionKey key : keys) {
if (key.isReadable()) {
// 읽기 가능한 채널 처리
read((SocketChannel) key.channel());
}
}
keys.clear();
}
}
// 1 스레드로 여러 채널 (이벤트 기반)
// busy polling 회피
public class NonBlockingResult {
// Polling (드물게 사용)
public Shipment pollResult(Future<Shipment> future) throws Exception {
int attempts = 0;
while (!future.isDone() && attempts < 100) {
Thread.sleep(50); // 적절한 간격
attempts++;
}
return future.isDone() ? future.get() : null;
}
// Callback (권장)
public void processWithCallback(Long id, Consumer<Shipment> onComplete) {
CompletableFuture
.supplyAsync(() -> repository.findById(id))
.thenAccept(onComplete)
.exceptionally(error -> {
log.error("Failed", error);
return null;
});
}
// 체이닝 (콜백의 발전)
public CompletableFuture<EnrichedShipment> enrichChain(Long id) {
return CompletableFuture
.supplyAsync(() -> repository.findById(id))
.thenCompose(this::fetchTrackingAsync)
.thenApply(this::buildEnriched);
}
}
논블로킹에서 결과 받기는?
답:
1. Polling:
Callback:
비교:
고급:
블로킹 시 스레드 상태:
I/O 블로킹:
- RUNNABLE (자바 관점)
- 또는 네이티브 대기
락 블로킹:
- BLOCKED (synchronized)
wait/join:
- WAITING
sleep/타임아웃:
- TIMED_WAITING
핵심:
- 블로킹 = CPU 안 씀 (대기)
- 상태는 원인에 따라
자바 스레드 상태 (Phase 3 에서 정밀):
RUNNABLE:
- 실행 또는 실행 가능
- I/O 대기도 RUNNABLE (자바 관점)
BLOCKED:
- synchronized 락 대기
WAITING:
- wait(), join() (무한)
TIMED_WAITING:
- sleep(ms), wait(ms)
블로킹 작업:
- I/O: RUNNABLE (네이티브 대기)
- 락: BLOCKED
I/O 블로킹은 RUNNABLE?:
자바 관점:
- I/O 블로킹 중에도 RUNNABLE
- 자바는 OS 대기를 모름
OS 관점:
- 실제론 대기 (CPU X)
- 대기 큐
이유:
- 자바 스레드 상태는 JVM 레벨
- OS 의 I/O 대기는 별개
→ jstack 에서 RUNNABLE 이지만
실제론 I/O 대기일 수 있음
블로킹 작업별 상태:
synchronized 대기:
스레드 → BLOCKED
(락 획득까지)
I/O read():
스레드 → RUNNABLE (자바)
→ 실제 OS 대기
Future.get():
스레드 → WAITING
sleep(100):
스레드 → TIMED_WAITING
블로킹의 영향 — 스레드 풀:
블로킹 작업이 많으면:
- 스레드가 대기로 점유
- 풀 고갈
- 새 작업 대기
예:
- 풀 크기 10
- 10개 작업이 모두 블로킹 I/O
- 11번째 작업 대기
해결:
- 풀 크기 ↑
- 논블로킹
- Virtual Thread
public class BlockingThreadState {
// 블로킹 작업이 스레드 점유
public void demonstrateBlocking() {
ExecutorService pool = Executors.newFixedThreadPool(10);
for (int i = 0; i < 10; i++) {
pool.submit(() -> {
// 블로킹 I/O (스레드 점유)
Shipment s = repository.findById(1L); // DB 대기
Tracking t = trackingApi.fetch(s.getBlNo()); // API 대기
// 이 스레드는 대기 중 점유
});
}
// 10 스레드 모두 블로킹 점유
// 11번째 작업은 대기
// 해결: Virtual Thread (Java 21+)
ExecutorService virtual = Executors.newVirtualThreadPerTaskExecutor();
// I/O 블로킹 시 OS 스레드 양보
// 수만 작업 가능
}
}
블로킹의 스레드 상태는?
답:
1. 상태:
I/O 특이점:
스레드 풀 영향:
해결:
논블로킹 I/O (NIO):
Java NIO (New I/O, Java 1.4+):
- Channel + Buffer + Selector
- 논블로킹 모드 지원
전통 I/O (블로킹):
- Stream
- read() 가 대기
NIO (논블로킹):
- Channel.configureBlocking(false)
- read() 즉시 반환
// 논블로킹 채널
SocketChannel channel = SocketChannel.open();
channel.configureBlocking(false); // 논블로킹 모드
ByteBuffer buffer = ByteBuffer.allocate(1024);
int read = channel.read(buffer);
// read 값:
// > 0: 읽은 바이트 수
// 0: 데이터 없음 (대기 X, 즉시 반환)
// -1: 연결 종료
if (read == 0) {
// 데이터 없음, 다른 일
}
// Selector — 1 스레드로 여러 채널
public void selectorPattern() throws IOException {
Selector selector = Selector.open();
// 여러 채널 등록
channel1.register(selector, SelectionKey.OP_READ);
channel2.register(selector, SelectionKey.OP_READ);
channel3.register(selector, SelectionKey.OP_READ);
while (true) {
selector.select(); // 준비된 채널까지 (효율적 대기)
Iterator<SelectionKey> keys = selector.selectedKeys().iterator();
while (keys.hasNext()) {
SelectionKey key = keys.next();
keys.remove();
if (key.isReadable()) {
// 준비된 채널만 처리
read((SocketChannel) key.channel());
}
}
}
}
// 1 스레드 + 여러 채널 = 효율
논블로킹 I/O 의 효과:
블로킹 I/O:
- 연결 1개 = 스레드 1개
- 1만 연결 = 1만 스레드
- 자원 폭발
논블로킹 I/O (Selector):
- 1 스레드로 여러 연결
- 1만 연결 = 적은 스레드
- C10K 문제 해결
예:
- Netty, Nginx
- 이벤트 루프
이벤트 루프 (Event Loop):
논블로킹 I/O 의 핵심 패턴.
동작:
while (true) {
events = selector.select(); // 이벤트 대기
for (event : events) {
handle(event); // 처리
}
}
- 1 스레드 (또는 적은 수)
- 이벤트 기반
- Netty, Node.js, Vert.x
// Spring WebFlux (논블로킹)
@RestController
public class ShipmentReactiveController {
private final ShipmentReactiveService service;
// 논블로킹 엔드포인트
@GetMapping("/api/shipments/{id}")
public Mono<Shipment> get(@PathVariable Long id) {
return service.findById(id); // 논블로킹
// 적은 스레드로 많은 요청
}
@GetMapping("/api/shipments")
public Flux<Shipment> getAll() {
return service.findAll(); // 논블로킹 스트림
}
}
@Service
public class ShipmentReactiveService {
private final R2dbcEntityTemplate template; // 논블로킹 DB
public Mono<Shipment> findById(Long id) {
return template.select(Shipment.class)
.matching(query(where("id").is(id)))
.one();
// 완전 논블로킹 (R2DBC)
}
}
논블로킹 I/O 의 동작은?
답:
1. NIO:
Channel:
Selector:
효과:
| Q | 핵심 답변 |
|---|---|
| 블로킹? | 완료까지 제어권 잃고 대기 |
| 논블로킹? | 즉시 제어권 반환 |
| 제어권? | 실행 흐름 제어 권리 |
| 판단 기준? | 제어권 가져갔나? |
| Sync vs Blocking? | 작업 순서 vs 제어권 |
| 논블로킹 결과? | polling, callback |
| Polling? | 반복 확인 |
| Callback? | 완료 통보 |
| 블로킹 스레드 상태? | I/O는 RUNNABLE(자바) |
| 논블로킹 I/O? | NIO, Selector |
| Selector? | 1 스레드 여러 채널 |
답:
답:
답:
답:
답:
1. Blocking vs Non-Blocking
2. 제어권 + Sync 구분
3. 결과 받기
이번 Unit에서 제어권 축을 봤다면, 다음은 두 축의 4가지 조합.
🚀 Phase 2 — Sync/Async × Blocking/Non-Blocking 4분면
✅ Unit 2.1 Sync vs Async (작업 순서)
✅ Unit 2.2 Blocking vs Non-Blocking (제어권) ← 여기
⏭ Unit 2.3 4분면 매트릭스 (★ 마스터)
✅ Phase 1 — 동시성의 기초 (4 Unit)
🚀 Phase 2 — 4분면 매트릭스 (2/3 진행)
총: 6/35 Unit