동시성 — 락·데드락·동기/비동기·블로킹/논블로킹
동시성 — 락·데드락·동기/비동기·블로킹/논블로킹
🎯 이 lesson 을 읽고 나면
이 lesson 을 다 읽고 나면 아래 3가지를 자신 있게 할 수 있습니다.
- ▸✅ Mutex vs Semaphore vs Monitor
- ▸✅ Race Condition + Deadlock 4조건
- ▸✅ 동기 vs 비동기 + 블로킹 vs 논블로킹 4조합
학습 목표를 체크리스트로 두고 다 답할 수 있게 되면 lesson 을 닫으세요.
Race Condition — 동시 수정의 비극
한 줄: 두 스레드가 같은 데이터를 동시 수정 → 결과 예측 불가.
예시:
이유: counter + 1 은 3개 명령:
1. read counter → register
2. register + 1
3. register → counter
A 가 1·2 후 B 가 1 하면 → 둘 다 0 읽고 +1 한 결과 1 만 저장.
해결:
Race 흔한 함정:
- ▸❌ 디버거 켜면 사라지는 버그 (Heisenbug) — 디버거가 타이밍 바꿈
- ▸❌ "내 컴퓨터에선 잘 됨" — CPU 코어 수·부하 다름
- ▸✅ 항상 동시성 테스트 (
-race플래그·ThreadSanitizer)
Mutex — 가장 흔한 락
Mutex (MUTual EXclusion): 한 번에 하나의 스레드만 임계 구역(critical section) 진입.
사용 흐름:
언어별 Mutex:
Mutex 흔한 실수:
ReadWriteLock: 읽기 다중 + 쓰기 단일 → 읽기 많은 워크로드에 유리.
Optimistic Lock: DB 에서 자주 사용. 충돌 시 재시도 (CAS 와 유사).
Deadlock — 영원한 대기
4 가지 필요 조건 (모두 충족 시 데드락):
1. 상호 배제 (Mutual Exclusion) — 자원이 한 번에 1 스레드만
2. 점유와 대기 (Hold and Wait) — 자원 잡고 다른 자원 기다림
3. 비선점 (No Preemption) — 강제 회수 불가
4. 순환 대기 (Circular Wait) — A→B→C→A 순환
고전 예: 두 락 잡는 순서가 스레드마다 다름:
→ 1 이 A 잡고 B 기다림 / 2 가 B 잡고 A 기다림 → 영원
해결 6가지:
데드락 디버깅:
- ▸Java:
jstack <PID>→ "Found one Java-level deadlock" 자동 감지 - ▸Python:
faulthandler+ thread dump - ▸Go:
go run -race(race detector) - ▸DB: PostgreSQL 자동 탐지 후 victim 트랜잭션 abort
동기 vs 비동기 · 블로킹 vs 논블로킹
4 가지 조합 (자주 혼동되므로 분리해서 이해):
동기/비동기 = 완료 통지 방식
블로킹/논블로킹 = 호출자 진행 여부
Linux I/O 모델 4가지:
epoll 동작 (Linux 의 효율적 I/O 멀티플렉싱):
1. epoll_create() — 인스턴스 생성
2. epoll_ctl(ADD) — 감시할 fd 등록
3. epoll_wait() — 이벤트 발생까지 블록
4. fd 처리 → 다시 wait
왜 Node.js·Nginx 가 빠른가 = 단일 스레드 + epoll 이벤트 루프 → 컨텍스트 스위칭 X.
🤖 AI 에게 이렇게 요청해보세요
이 lesson 의 개념을 알면 AI 에게 구체적으로 지시할 수 있습니다.
- ▸"이 메서드의 동시성 문제 분석해서 synchronized vs ReentrantLock 추천해줘."
- ▸"이 코드에 데드락 가능성 있는데 자원 획득 순서로 진단해줘."
- ▸"이 작업을 CompletableFuture + thenCombine 으로 병렬 처리해줘."
왜 이게 토큰을 줄이나
"락 / 데드락 / volatile / atomic" 어휘를 알면 AI 답변이 바로 코드 로 옵니다. 모르면 "동시성이란..." 부터 다시 설명 받아야 함.