DEV/cs

[CS] 데드락(Deadlock)이란 - 발생 조건과 해결 방법

강한 2026. 9. 17. 23:58

데드락이 뭐고 왜 생기는지, 발생하는 4가지 조건과 예방/해결 방법을 자바 예시와 함께 정리했습니다.


데드락이란

두 개 이상의 스레드(또는 프로세스)가 서로가 가진 자원을 기다리느라, 아무도 진행하지 못하고 영원히 멈춰버리는 상태입니다.

 
java
// 스레드 A: lock1을 잡고 lock2를 기다림
synchronized (lock1) {
    synchronized (lock2) { ... }
}

// 스레드 B: lock2를 잡고 lock1을 기다림
synchronized (lock2) {
    synchronized (lock1) { ... }
}

A가 lock1을 잡은 채 lock2를 기다리는데, 마침 B가 lock2를 잡은 채 lock1을 기다리고 있으면 둘 다 영원히 풀리지 않습니다. 이게 데드락입니다.

발생하는 4가지 조건

아래 조건이 전부 동시에 성립해야 데드락이 발생합니다. 하나라도 깨면 데드락을 막을 수 있습니다.

  • 상호 배제(Mutual Exclusion): 자원을 한 번에 하나의 스레드만 사용할 수 있음
  • 점유와 대기(Hold and Wait): 자원을 하나 잡은 채로, 다른 자원을 추가로 기다림
  • 비선점(No Preemption): 다른 스레드가 잡은 자원을 강제로 빼앗을 수 없음
  • 순환 대기(Circular Wait): A는 B의 자원을, B는 A의 자원을 기다리는 식으로 원형으로 물려 있음

해결 방법

1) 자원 접근 순서를 통일한다 (순환 대기 조건 제거)

가장 실무적인 방법입니다. 모든 스레드가 lock1 → lock2 순서로만 자원을 잡도록 강제하면, 순환이 생길 수 없습니다.

 
java
// A, B 모두 항상 lock1을 먼저 잡도록 통일
synchronized (lock1) {
    synchronized (lock2) { ... }
}

2) 자원을 기다리는 시간에 제한을 둔다 (점유와 대기 완화)

tryLock(timeout)처럼 일정 시간 안에 자원을 못 얻으면 포기하고 자기가 가진 자원도 풀어주게 합니다.

 
java
if (lock1.tryLock(1, TimeUnit.SECONDS)) {
    try {
        if (lock2.tryLock(1, TimeUnit.SECONDS)) {
            try { /* 작업 */ } finally { lock2.unlock(); }
        }
    } finally {
        lock1.unlock();
    }
}

3) 하나의 락만 사용하도록 설계를 단순화한다

애초에 여러 자원을 동시에 잡을 일이 없게 임계 영역을 재설계하는 방법입니다. 가장 근본적이지만 구조 변경이 필요합니다.

마무리

데드락은 "서로가 서로를 기다리며 아무도 못 움직이는 상태"이고, 상호 배제·점유와 대기·비선점·순환 대기 네 조건이 모두 맞아야 발생합니다. 실무에서는 이 중 순환 대기를 없애는 것, 즉 자원을 잡는 순서를 항상 동일하게 맞추는 방법이 가장 흔히 쓰입니다.