
안녕하세요, 이력서 기반 면접 준비를 도와드리는 QueryDaily 팀입니다.
"데드락이 무엇인가요?" "두 개 이상의 프로세스가 서로의 자원을 기다리며 무한정 대기하는 상태입니다!"
여기까지는 교과서적인 정답이죠. 그런데 면접관이 미소를 지으며 이렇게 묻는다면요?
"그럼 어떤 조건에서 데드락이 발생하나요? 실제로 겪어보신 적 있으세요?"
.
.
.
혹시 머릿속이 멈칫하는 경험, 없으신가요? 괜찮습니다. 많은 개발자들이 데드락의 정의는 알지만, 발생 조건과 해결 방법까지 깊이 있게 설명하기는 어려워합니다. 오늘은 데드락의 발생 조건 4가지부터 해결 전략, 그리고 실무에서 마주치는 상황까지 면접에서 바로 써먹을 수 있도록 정리해 보겠습니다.
데드락은 쉽게 말해 "교착 상태"입니다. 비유하자면, 좁은 골목길에서 두 대의 차가 마주 보고 있는 상황을 생각해 보세요.
🚗 → ← 🚙
↑
좁은 골목
둘 다 상대방이 먼저 양보하길 기다리며 아무도 움직이지 않습니다. 이것이 바로 데드락입니다.
컴퓨터 시스템에서는 이렇게 표현할 수 있습니다:
[프로세스 A] [프로세스 B]
| |
| 자원 X 보유 | 자원 Y 보유
| 자원 Y 대기 ←──────────→ | 자원 X 대기
| |
↓ ↓
무한 대기 무한 대기
핵심 포인트: 데드락은 각 프로세스가 자신이 가진 자원은 놓지 않으면서, 상대방이 가진 자원을 요청할 때 발생합니다.
데드락이 발생하려면 반드시 4가지 조건이 동시에 만족되어야 합니다. 이를 Coffman 조건이라고 부릅니다. 면접에서 자주 물어보는 핵심 내용이니 꼭 기억하세요!
1. 상호 배제 (Mutual Exclusion)
자원은 한 번에 하나의 프로세스만 사용할 수 있습니다.
// 프린터는 동시에 두 문서를 출력할 수 없다
synchronized(printer) {
printer.print(document);
}
2. 점유와 대기 (Hold and Wait)
자원을 보유한 채로 다른 자원을 기다립니다.
// A를 가진 상태에서 B를 기다림
synchronized(resourceA) {
// resourceA 보유 중...
synchronized(resourceB) { // resourceB 대기
// 작업 수행
}
}
3. 비선점 (No Preemption)
다른 프로세스가 사용 중인 자원을 강제로 빼앗을 수 없습니다.
프로세스 A가 프린터를 사용 중
→ 프로세스 B는 강제로 프린터를 빼앗을 수 없음
→ A가 스스로 반납할 때까지 대기해야 함
P1 → P2 → P3 → P1 (순환!)
P1: P2가 가진 자원 대기
P2: P3이 가진 자원 대기
P3: P1이 가진 자원 대기
⚠️ 중요: 이 4가지 조건 중 하나라도 깨트리면 데드락은 발생하지 않습니다. 이것이 데드락 해결의 핵심 원리입니다.
데드락을 다루는 방법은 크게 4가지로 나눌 수 있습니다.
1. 예방 (Prevention) - 조건을 원천 차단
4가지 조건 중 하나를 아예 만족하지 못하게 설계합니다.
조건 예방 방법
- 상호 배제 자원을 공유 가능하게 (현실적으로 어려움)
- 점유와 대기 필요한 모든 자원을 한 번에 요청
- 비선점 자원을 강제로 회수 가능하게
- 순환 대기 자원에 번호를 부여, 오름차순으로만 요청 ✅
가장 실용적인 방법은 순환 대기를 깨는 것입니다:
// ❌ 데드락 위험: 순서 없이 자원 요청
// Thread 1: lockA → lockB
// Thread 2: lockB → lockA
// ✅ 안전: 항상 같은 순서로 자원 요청
// 모든 스레드: lockA → lockB (번호순)
public void safeMethod() {
synchronized(lockA) { // 항상 A 먼저
synchronized(lockB) { // 그 다음 B
// 작업 수행
}
}
}
2. 회피 (Avoidance) - 은행원 알고리즘
자원을 할당하기 전에 "이 할당이 안전한가?"를 미리 검사합니다. 대표적인 알고리즘이 은행원 알고리즘(Banker's Algorithm)입니다.
[은행원의 비유]
은행에 현금 10억이 있고, 고객 A, B, C가 각각 대출을 요청한다.
- 고객 A: 최대 5억 필요, 현재 2억 대출
- 고객 B: 최대 4억 필요, 현재 2억 대출
- 고객 C: 최대 7억 필요, 현재 3억 대출
남은 현금: 3억
만약 A가 3억을 더 요청한다면?
→ A에게 3억 대출 → A 완료 후 5억 회수 → 안전! ✅
→ 다른 고객도 순차적으로 처리 가능
만약 C가 4억을 요청한다면?
→ 현금이 3억뿐이라 불가능 → 거절! ❌
핵심: 모든 프로세스가 완료될 수 있는 "안전 순서"가 존재하면 자원을 할당합니다.
3. 탐지와 복구 (Detection & Recovery)
데드락이 발생하도록 허용하되, 주기적으로 감시하다가 발견하면 복구합니다.
탐지 방법:
자원 할당 그래프에서 사이클을 탐지
주기적으로 시스템 상태 검사
복구 방법:
프로세스 종료: 데드락에 관련된 프로세스 중 하나를 강제 종료
자원 선점: 특정 프로세스의 자원을 강제로 회수
탐지 → 데드락 발견!
복구 → P1 강제 종료 → P2, P3 정상 진행
4. 무시 (Ignorance) - 타조 알고리즘
데드락이 발생할 확률이 매우 낮다면, 그냥 무시하는 전략입니다. 실제로 Unix, Linux, Windows 등 대부분의 운영체제가 이 방식을 사용합니다.
왜? 데드락 예방/회피/탐지에 드는 오버헤드가 데드락으로 인한 손실보다 클 수 있기 때문입니다.
1. 데이터베이스 트랜잭션 데드락
-- 트랜잭션 1
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1; -- Row 1 락
UPDATE accounts SET balance = balance + 100 WHERE id = 2; -- Row 2 대기
-- 트랜잭션 2 (동시 실행)
BEGIN;
UPDATE accounts SET balance = balance - 50 WHERE id = 2; -- Row 2 락
UPDATE accounts SET balance = balance + 50 WHERE id = 1; -- Row 1 대기
-- 데드락 발생! 🔒
해결: 항상 같은 순서로 테이블/로우에 접근하거나, 트랜잭션 타임아웃 설정
2. Java 멀티스레드 데드락
public class DeadlockExample {
private final Object lock1 = new Object();
private final Object lock2 = new Object();
public void method1() {
synchronized (lock1) {
System.out.println("Thread 1: lock1 획득");
synchronized (lock2) { // lock2 대기
System.out.println("Thread 1: lock2 획득");
}
}
}
public void method2() {
synchronized (lock2) {
System.out.println("Thread 2: lock2 획득");
synchronized (lock1) { // lock1 대기 → 데드락!
System.out.println("Thread 2: lock1 획득");
}
}
}
}
해결: 락 획득 순서를 통일하거나, tryLock()으로 타임아웃 설정
// 개선된 코드: 락 순서 통일
public void method2_safe() {
synchronized (lock1) { // lock1 먼저!
synchronized (lock2) {
// 안전하게 작업 수행
}
}
}
자, 이제 면접관의 깊이 있는 질문들에 대비해 봅시다.
Q1. "데드락 발생 조건 4가지를 말씀해주세요."
A: "상호 배제, 점유와 대기, 비선점, 순환 대기입니다. 이 4가지 조건이 동시에 만족될 때 데드락이 발생하며, 하나라도 깨트리면 데드락을 예방할 수 있습니다."
Q2. "실무에서 데드락을 어떻게 예방하시나요?"
A: "가장 실용적인 방법은 락 순서를 통일하는 것입니다. 모든 스레드가 자원을 동일한 순서로 요청하면 순환 대기 조건이 깨져 데드락이 발생하지 않습니다. DB에서는 트랜잭션 타임아웃 설정과 함께, 테이블 접근 순서를 일관되게 유지합니다."
Q3. "데드락과 라이브락(Livelock)의 차이는 무엇인가요?"
A: "데드락은 프로세스들이 아무것도 하지 않고 무한 대기하는 상태입니다. 반면 라이브락은 프로세스들이 상태를 계속 변경하지만 실제로 진전이 없는 상태입니다. 마치 좁은 복도에서 두 사람이 서로 비켜주려고 같은 방향으로 계속 움직이는 것과 같습니다."
Q4. "기아 상태(Starvation)와 데드락의 차이점은요?"
A: "데드락은 관련된 프로세스들이 모두 영원히 진행하지 못합니다. 기아 상태는 특정 프로세스만 자원을 계속 얻지 못하고, 다른 프로세스들은 정상적으로 진행됩니다. 기아 상태는 우선순위가 낮은 프로세스가 계속 밀려날 때 발생할 수 있습니다."
✅ 데드락은 프로세스들이 서로의 자원을 기다리며 영원히 진행하지 못하는 상태입니다.
✅ 4가지 조건(상호 배제, 점유와 대기, 비선점, 순환 대기)이 동시에 만족되어야 발생합니다.
✅ 가장 실용적인 예방법은 자원 요청 순서를 통일하여 순환 대기를 깨는 것입니다.
✅ 실무에서는 DB 트랜잭션 데드락, 멀티스레드 데드락을 자주 마주치게 됩니다.
오늘 다룬 것처럼, CS 기초 개념을 단순히 정의만 외우는 것이 아니라 "왜 발생하는지", "어떻게 해결하는지"까지 설명할 수 있어야 면접에서 차별화됩니다.
이력서에 적힌 '멀티스레드 환경 개발 경험' 한 줄에서 이런 깊이 있는 꼬리 질문들이 이어질 수 있다는 것, 알고 계시죠? QueryDaily는 여러분의 이력서를 분석하여 이런 꼬리 질문들을 매일 제공해 드립니다.
#데드락 #Deadlock #운영체제 #OS #면접 #CS기초 #백엔드면접 #멀티스레드