반응형
데드락(교착 상태)란?
데드락(Deadlock)은 둘 이상의 스레드가 서로가 점유한 자원을 기다리며 무한히 대기하게 되는 상태를 말한다. 한국어로는 일반적으로 "교착 상태"라고 하며, 다중 스레드 환경에서 자주 발생할 수 있는 대표적인 병목 현상 중 하나이다.
1. 데드락 발생 조건 (Coffman Conditions)
데드락은 다음 네 가지 조건이 모두 충족될 때 발생한다:
- 상호 배제 (Mutual Exclusion): 자원은 한 번에 하나의 스레드만 사용할 수 있다.
- 점유 및 대기 (Hold and Wait): 자원을 점유한 상태에서 다른 자원을 기다린다.
- 비선점 (No Preemption): 자원을 강제로 회수할 수 없다.
- 순환 대기 (Circular Wait): 스레드들이 자원을 서로 기다리며 원형 대기를 형성한다.
2. 데드락 예시 (JAVA)
아래 코드는 A와 B라는 객체를 두 개의 스레드가 교차로 접근하면서 데드락이 발생할 수 있는 상황을 보여준다.
class A {
synchronized void methodA(B b) {
System.out.println("Thread 1: Locked A");
try { Thread.sleep(100); } catch (InterruptedException e) {}
b.last();
}
synchronized void last() {
System.out.println("Thread 1: Executing last");
}
}
class B {
synchronized void methodB(A a) {
System.out.println("Thread 2: Locked B");
try { Thread.sleep(100); } catch (InterruptedException e) {}
a.last();
}
synchronized void last() {
System.out.println("Thread 2: Executing last");
}
}
public class DeadlockExample {
public static void main(String[] args) {
A a = new A();
B b = new B();
Thread t1 = new Thread(() -> a.methodA(b));
Thread t2 = new Thread(() -> b.methodB(a));
t1.start();
t2.start();
}
}
3. 데드락 방지 방법 및 예시
3.1 자원 요청 순서 지정 (Resource Ordering)
스레드들이 자원을 항상 일정한 순서로 요청하도록 강제하면, 순환 대기를 원천 차단할 수 있다.
// 항상 A를 먼저 잠그고 B를 나중에 잠그도록 설계
synchronized (lockA) {
synchronized (lockB) {
// 안전하게 작업 수행
}
}
3.2 타임아웃 사용 (tryLock)
ReentrantLock의 tryLock()을 사용하면, 일정 시간 안에 락을 획득하지 못할 경우 포기할 수 있어 데드락을 방지할 수 있다.
Lock lockA = new ReentrantLock();
Lock lockB = new ReentrantLock();
if (lockA.tryLock(100, TimeUnit.MILLISECONDS)) {
try {
if (lockB.tryLock(100, TimeUnit.MILLISECONDS)) {
try {
// 작업 수행
} finally {
lockB.unlock();
}
}
} finally {
lockA.unlock();
}
}
3.3 스레드 실행 순서 제어 (join() 활용)
join()을 이용하면 특정 스레드가 종료될 때까지 다른 스레드가 기다리게 할 수 있습니다. 이를 통해 자원 접근 순서를 통제할 수 있어 데드락 가능성을 줄일 수 있다.
Thread t1 = new Task1();
Thread t2 = new Task2();
t1.start();
t1.join(); // t2는 t1이 끝난 후 실행
t2.start();
3.4 비차단 설계 (Non-blocking Design)
락을 아예 사용하지 않고, 상태 기반 조건문 등을 통해 자원 접근을 동기화하는 방식이다. 자바의 AtomicInteger 같은 원자 클래스나 CAS(Compare-And-Swap) 기법을 활용할 수 있다.
3.4 데드락 감지 및 복구
자바 자체에서는 데드락 감지 기능이 내장되어 있지 않지만, ThreadMXBean 등의 JMX 도구를 사용하여 데드락을 탐지할 수 있으며, 필요한 경우 관리자 권한으로 프로세스를 재시작하거나 해당 스레드를 종료시켜 복구할 수 있다.
- 자바에서는 synchronized, Lock, join() 등을 사용할 때 자원 접근 순서와 타이밍에 주의해야 한다.
- 데드락을 방지하려면 사전 설계 단계에서부터 일관된 자원 접근 규칙을 정의하는 것이 중요하다.
반응형
'Programming > Java' 카테고리의 다른 글
면접에서 진짜 자주 나오는 자바 질문 - 섹션 1. 자바 기본 개념 (1) | 2025.04.17 |
---|---|
쓰레드 풀(Thread Pool)의 개념과 최적화 방법 (1) | 2025.04.15 |
JAVA synchronized 키워드와 ReentrantLock의 차이점 (멀티스레딩) (0) | 2025.04.15 |
JAVA final, finally, finalize의 차이점 정리 (0) | 2025.04.15 |
JAVA 불변 객체(Immutable Object)란 무엇이며, 어떻게 만들 수 있을까 (0) | 2025.04.15 |