쓰레드 프로그램에서 여러 사람이 동시에 사용 중에 데드락(교착 상태, Deadlock)이 발생하는 경우는 다음과 같은 상황에서 주로 나타납니다.

1. 상호 배제 (Mutual Exclusion)

  • 공유 자원이 동시에 여러 쓰레드에 의해 사용되지 않도록 하기 위해 락(Lock)을 사용하는 경우.
  • 특정 자원이 한 번에 하나의 쓰레드만 사용할 수 있도록 제한되기 때문에 다른 쓰레드가 자원을 대기하게 됩니다.

2. 점유 및 대기 (Hold and Wait)

  • 한 쓰레드가 이미 락을 점유한 상태에서 다른 자원을 요청하지만, 그 자원이 다른 쓰레드에 의해 점유되고 있는 상황.
  • 이미 점유한 락을 해제하지 않고 대기하면서 교착 상태가 발생합니다.

3. 비선점 (No Preemption)

  • 점유한 자원을 강제로 회수하지 못하는 경우.
  • 즉, 쓰레드가 스스로 자원을 반환할 때까지 기다려야 하며, 대기 상태가 해결되지 않을 가능성이 있습니다.

4. 순환 대기 (Circular Wait)

  • 두 개 이상의 쓰레드가 서로 자원을 대기하면서 순환 구조가 형성되는 경우.
  • 예:
    • 쓰레드 A는 자원 1을 점유하고 자원 2를 요청.
    • 쓰레드 B는 자원 2를 점유하고 자원 1을 요청.

데드락 발생 예시

class DeadlockExample {
    private final Object lock1 = new Object();
    private final Object lock2 = new Object();

    public void method1() {
        synchronized (lock1) {
            System.out.println("Thread 1: Holding lock1...");
            try { Thread.sleep(100); } catch (InterruptedException e) {}
            System.out.println("Thread 1: Waiting for lock2...");
            synchronized (lock2) {
                System.out.println("Thread 1: Acquired lock2!");
            }
        }
    }

    public void method2() {
        synchronized (lock2) {
            System.out.println("Thread 2: Holding lock2...");
            try { Thread.sleep(100); } catch (InterruptedException e) {}
            System.out.println("Thread 2: Waiting for lock1...");
            synchronized (lock1) {
                System.out.println("Thread 2: Acquired lock1!");
            }
        }
    }
}

public class DeadlockTest {
    public static void main(String[] args) {
        DeadlockExample example = new DeadlockExample();

        Thread t1 = new Thread(example::method1);
        Thread t2 = new Thread(example::method2);

        t1.start();
        t2.start();
    }
}

설명

  • Thread 1은 lock1을 점유하고 lock2를 요청.
  • 동시에, Thread 2는 lock2를 점유하고 lock1을 요청.
  • 두 쓰레드가 서로를 기다리며 순환 대기 상태가 발생하여 데드락이 생깁니다.

데드락 방지 방법

  1. 자원 획득 순서 지정
    • 모든 쓰레드가 자원을 요청하는 순서를 동일하게 유지합니다.
  2. 타임아웃 설정
    • 자원 요청 시 일정 시간 대기 후 실패로 처리하여 데드락을 방지합니다.
  3. 데드락 감지 및 회복
    • 데드락 감지 알고리즘을 통해 순환 대기를 탐지하고 적절히 해소합니다.
  4. 자원 회수
    • 자원 점유가 너무 길어지면 강제로 회수하는 방법을 고려합니다.
  5. 락 분해 (Lock Granularity 감소)
    • 큰 락을 여러 작은 락으로 분리하여 동시성을 높이고 데드락 가능성을 줄입니다.

+ Recent posts