4주차 Unit 3.1 — 스레드 상태 다이어그램

Psj·2026년 5월 20일

F-lab

목록 보기
127/240

Unit 3.1 — 스레드 상태 다이어그램

F-LAB JAVA · 4주차 · Phase 3 · 스레드 만들고 다루기
🚀 Phase 3 시작 — 스레드 실전 진입


📌 학습 목표

이 Unit을 끝내면 다음을 답할 수 있어야 한다.

  • 자바 스레드의 6가지 상태 는?
  • NEW → RUNNABLE → TERMINATED 의 흐름은?
  • BLOCKED / WAITING / TIMED_WAITING 의 차이는?
  • 각 상태 전이 (start/wait/join/sleep) 의 트리거는?
  • BLOCKED 와 WAITING 의 차이 (깨어나는 조건) 는?
  • getState() 가 RUNNING 을 반환 할 수 있는가?
  • RUNNABLE 의 두 의미 (실행 중 + 실행 가능) 는?
  • 상태별 깨어나는 방법 은?
  • jstack 으로 상태를 보는 법은?

🎯 핵심 한 문장

자바 스레드는 Thread.State enum 으로 정의된 6가지 상태 (NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED) 를 가지며, 이벤트에 따라 상태가 전이된다.
NEW (생성됨, 미시작) → start()RUNNABLE (실행 중 또는 실행 가능) → run 종료 → TERMINATED (종료).
RUNNABLE 에서 BLOCKED (synchronized 락 대기), WAITING (wait/join, 무한 대기), TIMED_WAITING (sleep/wait(ms), 시간 한정) 으로 빠질 수 있다.
BLOCKED 는 락 반납 시 깨어나고, WAITING 은 notify/join 대상 종료 시 깨어난다는 점이 다르다.
자바에는 별도의 RUNNING 상태가 없으며 (RUNNABLE 에 포함), 실제 CPU 실행 여부는 OS 스케줄러가 결정하므로 getState() 는 RUNNING 을 반환하지 않는다.

비유 — 회의실 사용

NEW: 회의 예약함 (아직 시작 X)
  - Thread 객체 생성

RUNNABLE: 회의실 사용 중 또는 대기열
  - 실행 중 (CPU 할당)
  - 또는 실행 가능 (스케줄러 대기)

BLOCKED: 회의실 문이 잠김 (다른 사람 사용)
  - synchronized 락 대기
  - 락 풀리면 들어감

WAITING: "알려주면 올게요" (무한 대기)
  - wait(): notify 까지
  - join(): 대상 종료까지

TIMED_WAITING: "30분 후 올게요" (시간 한정)
  - sleep(ms)
  - wait(ms)

TERMINATED: 회의 끝남
  - run 종료

→ 6가지 상태 = 스레드의 생애 주기.


🧭 9개 섹션 로드맵

1. 6가지 상태 개요
2. NEW와 RUNNABLE
3. RUNNABLE의 두 의미
4. BLOCKED
5. WAITING
6. TIMED_WAITING
7. TERMINATED와 상태 전이
8. getState()와 RUNNING
9. 면접 + 자기 점검

1️⃣ 6가지 상태 개요

1.1 Thread.State enum

public enum Thread.State {
    NEW,            // 생성됨, 미시작
    RUNNABLE,       // 실행 중 또는 실행 가능
    BLOCKED,        // 모니터 락 대기
    WAITING,        // 무한 대기 (wait, join)
    TIMED_WAITING,  // 시간 한정 대기 (sleep, wait(ms))
    TERMINATED      // 종료
}

1.2 상태 다이어그램

       new Thread()
            ↓
        ┌───────┐
        │  NEW  │
        └───┬───┘
            │ start()
            ↓
    ┌───────────────┐
    │   RUNNABLE    │ ←──────────┐
    └───┬───┬───┬───┘            │
        │   │   │                │
   락대기│ wait│ sleep            │
        │ join│ wait(ms)         │
        ↓   ↓   ↓                │
   ┌────────┐ ┌────────┐ ┌──────────────┐
   │BLOCKED │ │WAITING │ │TIMED_WAITING │
   └────┬───┘ └───┬────┘ └──────┬───────┘
        │         │             │
        └─────────┴─────────────┘ (조건 충족 시 복귀)
            │
       run() 종료
            ↓
      ┌────────────┐
      │ TERMINATED │
      └────────────┘

1.3 상태별 요약

상태의미진입 트리거탈출 조건
NEW생성, 미시작new Thread()start()
RUNNABLE실행/실행 가능start()작업 종료, 대기
BLOCKED락 대기synchronized락 획득
WAITING무한 대기wait(), join()notify, 종료
TIMED_WAITING시간 대기sleep, wait(ms)시간 경과, notify
TERMINATED종료run 종료(최종)

1.4 상태 확인

Thread t = new Thread(() -> {
    // 작업
});

System.out.println(t.getState());   // NEW

t.start();
System.out.println(t.getState());   // RUNNABLE (보통)

// 다른 스레드에서 확인
Thread.sleep(100);
System.out.println(t.getState());   // 상태에 따라

1.5 ILIC 의 맥락

public class ShipmentThreadMonitor {
    
    public void monitorWorker(Thread worker) {
        Thread.State state = worker.getState();
        
        switch (state) {
            case NEW -> log.info("Worker not started");
            case RUNNABLE -> log.info("Worker running");
            case BLOCKED -> log.warn("Worker blocked on lock!");
            case WAITING -> log.info("Worker waiting");
            case TIMED_WAITING -> log.info("Worker sleeping");
            case TERMINATED -> log.info("Worker finished");
        }
    }
    
    // 데드락 감지 (BLOCKED 가 많으면 의심)
    public boolean detectPotentialDeadlock(List<Thread> workers) {
        long blockedCount = workers.stream()
            .filter(t -> t.getState() == Thread.State.BLOCKED)
            .count();
        return blockedCount > workers.size() / 2;
    }
}

1.6 자기 점검 답변

6가지 상태는?

:
1. NEW: 생성, 미시작
2. RUNNABLE: 실행/실행 가능
3. BLOCKED: 락 대기
4. WAITING: 무한 대기 (wait/join)
5. TIMED_WAITING: 시간 대기 (sleep)
6. TERMINATED: 종료

확인: t.getState() → Thread.State enum


2️⃣ NEW와 RUNNABLE

2.1 NEW 상태

NEW:

  Thread 객체가 생성되었지만
  아직 start() 호출 전.

특징:
  - 스레드 미시작
  - OS 스레드 없음
  - start() 로 RUNNABLE 전이

2.2 NEW 예시

Thread t = new Thread(() -> System.out.println("Hello"));
// 이 시점 NEW

System.out.println(t.getState());   // NEW

// 아직 실행 X
// OS 레벨 스레드 없음

2.3 RUNNABLE 진입

Thread t = new Thread(() -> {
    // 작업
});

t.start();   // NEW → RUNNABLE
// OS 스레드 생성
// 실행 시작 (또는 실행 대기)

System.out.println(t.getState());   // RUNNABLE

2.4 start() vs run()

// start() — 새 스레드
t.start();
// - NEW → RUNNABLE
// - 새 OS 스레드
// - run() 이 새 스레드에서 실행

// run() — 메서드 호출
t.run();
// - 상태 전이 X
// - 현재 스레드에서 실행
// - 새 스레드 X
// (Unit 3.2 에서 정밀)

2.5 시각화

NEW → RUNNABLE:

new Thread()
    ↓
[NEW]
  Thread 객체만 (OS 스레드 X)
    ↓ start()
[RUNNABLE]
  OS 스레드 생성
  실행 또는 실행 가능

2.6 ILIC 의 맥락

public class ShipmentWorkerLifecycle {
    
    public void demonstrateLifecycle() {
        // NEW
        Thread worker = new Thread(() -> {
            processShipments();
        });
        log.info("State: {}", worker.getState());   // NEW
        
        // RUNNABLE
        worker.start();
        log.info("State: {}", worker.getState());   // RUNNABLE
        
        // 주의: start() 두 번 호출하면 IllegalThreadStateException
        // worker.start();   // ❌ 예외
    }
    
    private void processShipments() {
        // 작업
    }
}

2.7 자기 점검 답변

NEW와 RUNNABLE은?

:
1. NEW:

  • Thread 객체 생성
  • 미시작
  • OS 스레드 X
  1. RUNNABLE:

    • start() 후
    • OS 스레드 생성
    • 실행/실행 가능
  2. 전이:

    • NEW → start() → RUNNABLE
  3. start() vs run():

    • start(): 새 스레드
    • run(): 메서드 호출

3️⃣ RUNNABLE의 두 의미

3.1 RUNNABLE 의 포괄성

RUNNABLE 의 두 가지 의미:

1. 실제 실행 중 (Running)
   - CPU 할당받아 실행

2. 실행 가능 (Ready)
   - 실행 준비됨
   - CPU 대기 (스케줄러 큐)

자바는 둘을 구분 안 함
→ 모두 RUNNABLE

3.2 왜 구분 안 하나

RUNNABLE 이 포괄적인 이유:

  실행 중 ↔ 실행 가능 전이는
  OS 스케줄러가 매우 빠르게.

  자바가 추적하기엔:
    - 너무 빠른 전이
    - OS 레벨 정보
    - 의미 적음

  → 하나로 묶음 (RUNNABLE)

3.3 시각화

RUNNABLE 내부:

[RUNNABLE]
  ┌─────────────┐
  │ Running     │ ← CPU 실행 중
  │   ↕ (스케줄러)│
  │ Ready       │ ← CPU 대기
  └─────────────┘

  자바 관점: 둘 다 RUNNABLE
  OS 관점: 구분 (Running/Ready)

3.4 I/O 대기와 RUNNABLE

I/O 블로킹도 RUNNABLE:

  네트워크/파일 I/O 대기 중에도
  자바는 RUNNABLE 로 표시.

이유:
  - I/O 대기는 OS 레벨
  - 자바 스레드 상태는 JVM 레벨
  - JVM 은 OS I/O 대기 모름

→ jstack 에서 RUNNABLE 이지만
   실제론 I/O 대기일 수 있음

3.5 RUNNABLE 의 함정

// jstack 결과 해석 주의
public void ioOperation() {
    // 이 스레드는 RUNNABLE (자바)
    byte[] data = socket.getInputStream().readAllBytes();
    // 실제론 네트워크 I/O 대기
    // 하지만 상태는 RUNNABLE
}

// 진단 시:
// - RUNNABLE 인데 CPU 안 쓰면
// - I/O 대기 의심
// - 스택 트레이스로 확인 (socketRead 등)

3.6 ILIC 의 맥락

public class RunnableStateExample {
    
    public void demonstrateRunnable() {
        Thread worker = new Thread(() -> {
            // CPU 작업 (Running)
            long sum = computeSum();
            
            // I/O 작업 (RUNNABLE 이지만 실제 대기)
            Shipment s = repository.findById(1L);
            
            // 둘 다 자바 관점 RUNNABLE
        });
        worker.start();
        
        // 모니터링
        log.info("State: {}", worker.getState());   // RUNNABLE
        // CPU 실행 중인지 I/O 대기인지 구분 안 됨
    }
    
    private long computeSum() {
        long sum = 0;
        for (int i = 0; i < 1_000_000; i++) sum += i;
        return sum;
    }
}

3.7 자기 점검 답변

RUNNABLE의 두 의미는?

:
1. 두 의미:

  • 실행 중 (Running)
  • 실행 가능 (Ready, CPU 대기)
  1. 구분 안 하는 이유:

    • 너무 빠른 전이
    • OS 레벨
    • 의미 적음
  2. I/O 대기:

    • 자바: RUNNABLE
    • 실제: OS 대기
  3. 진단:

    • RUNNABLE + CPU 안 씀 = I/O 의심
    • 스택 트레이스 확인

4️⃣ BLOCKED

4.1 BLOCKED 의 정의

BLOCKED:

  synchronized 모니터 락을
  획득하지 못해 대기하는 상태.

특징:
  - 다른 스레드가 락 보유 중
  - 락 반납까지 대기
  - 락 획득 시 RUNNABLE 복귀

4.2 BLOCKED 진입

class Counter {
    private int count = 0;
    
    public synchronized void increment() {
        count++;   // 모니터 락 필요
    }
}

// 스레드 A 가 increment() 실행 중 (락 보유)
// 스레드 B 가 increment() 호출
// → B 는 BLOCKED (락 대기)

4.3 시각화

BLOCKED 시나리오:

스레드 A:
  synchronized 진입 (락 획득)
  → RUNNABLE
  작업 중...

스레드 B:
  synchronized 진입 시도
  → 락 없음
  → BLOCKED (대기)

스레드 A:
  synchronized 종료 (락 반납)

스레드 B:
  → 락 획득
  → RUNNABLE 복귀

4.4 BLOCKED 의 깨어남

BLOCKED → RUNNABLE:

  조건: 락이 반납됨

  - 락 보유 스레드가 synchronized 종료
  - BLOCKED 스레드 중 하나가 락 획득
  - RUNNABLE 복귀

특징:
  - 락 반납이 유일한 조건
  - notify 등으로 깨우는 것 X (다른 메커니즘)

4.5 BLOCKED 의 위험

BLOCKED 가 많으면:

  - 락 경합 심함
  - 성능 저하
  - 데드락 의심

진단:
  - jstack 으로 BLOCKED 확인
  - 어떤 락 대기하는지
  - 데드락 감지

4.6 ILIC 의 맥락

@Service
public class ShipmentSyncService {
    
    private final Object lock = new Object();
    private int processedCount = 0;
    
    public void process(Shipment shipment) {
        // 여러 스레드 동시 호출 시
        synchronized (lock) {   // 락 경합
            // 한 스레드만 진입 (RUNNABLE)
            // 나머지는 BLOCKED
            processedCount++;
            doWork(shipment);
        }
    }
    
    private void doWork(Shipment s) {
        // 작업 (이 동안 다른 스레드 BLOCKED)
    }
}

// 모니터링: 많은 스레드가 BLOCKED 면
// → 락 경합 → synchronized 범위 줄이기 검토

4.7 자기 점검 답변

BLOCKED는?

:
1. 정의:

  • synchronized 락 대기
  • 다른 스레드가 락 보유
  1. 진입:

    • synchronized 진입 시 락 없으면
  2. 깨어남:

    • 락 반납 시
    • 락 획득 → RUNNABLE
  3. 위험:

    • 많으면 락 경합
    • 데드락 의심

5️⃣ WAITING

5.1 WAITING 의 정의

WAITING:

  무한 대기 상태.
  다른 스레드의 특정 동작까지 대기.

진입:
  - Object.wait() (notify 까지)
  - Thread.join() (대상 종료까지)
  - LockSupport.park() (unpark 까지)

5.2 wait() 로 진입

synchronized (lock) {
    while (condition) {
        lock.wait();   // RUNNABLE → WAITING
        // 락 반납 + 대기
        // notify/notifyAll 까지
    }
}

5.3 join() 으로 진입

Thread worker = new Thread(() -> doWork());
worker.start();

worker.join();   // 현재 스레드 RUNNABLE → WAITING
// worker 종료까지 대기
// worker 종료 시 RUNNABLE 복귀

5.4 WAITING 의 깨어남

WAITING → RUNNABLE:

wait() 로 진입:
  - notify() / notifyAll() 호출 시
  - (단, 락 재획득 필요)

join() 으로 진입:
  - 대상 스레드 종료 시

park() 로 진입:
  - unpark() 호출 시
  - 인터럽트

5.5 BLOCKED vs WAITING

BLOCKED vs WAITING 차이:

BLOCKED:
  - 락 획득 실패 (synchronized 진입)
  - 깨어남: 락 반납
  - 수동적 (락 경쟁)

WAITING:
  - 자발적 대기 (wait/join)
  - 깨어남: notify / 대상 종료
  - 능동적 (조건 대기)

핵심:
  - BLOCKED: 락 때문에
  - WAITING: 조건/이벤트 대기

5.6 시각화

WAITING 시나리오 (wait/notify):

스레드 A:
  synchronized(lock) {
    lock.wait();   → WAITING (락 반납)
  }

스레드 B:
  synchronized(lock) {
    lock.notify();   // A 깨움
  }

스레드 A:
  → 락 재획득 시도
  → RUNNABLE 복귀

5.7 ILIC 의 맥락

@Service
public class ShipmentQueueProcessor {
    
    private final Object lock = new Object();
    private final Queue<Shipment> queue = new LinkedList<>();
    
    // 소비자 — WAITING (큐 비면 대기)
    public Shipment consume() throws InterruptedException {
        synchronized (lock) {
            while (queue.isEmpty()) {
                lock.wait();   // WAITING (데이터 올 때까지)
            }
            return queue.poll();
        }
    }
    
    // 생산자 — notify (대기 깨움)
    public void produce(Shipment shipment) {
        synchronized (lock) {
            queue.offer(shipment);
            lock.notify();   // WAITING 소비자 깨움
        }
    }
    
    // join 예시
    public void waitForWorker(Thread worker) throws InterruptedException {
        worker.join();   // 현재 스레드 WAITING (worker 종료까지)
    }
}

5.8 자기 점검 답변

WAITING은?

:
1. 정의:

  • 무한 대기
  • 특정 동작까지
  1. 진입:

    • wait() (notify 까지)
    • join() (종료까지)
    • park() (unpark 까지)
  2. 깨어남:

    • notify/notifyAll
    • 대상 종료
    • unpark
  3. vs BLOCKED:

    • BLOCKED: 락 때문 (수동)
    • WAITING: 조건 대기 (자발)

6️⃣ TIMED_WAITING

6.1 TIMED_WAITING 의 정의

TIMED_WAITING:

  시간 제한이 있는 대기.
  지정 시간 경과 또는 조건 충족 시 깨어남.

진입:
  - Thread.sleep(ms)
  - Object.wait(ms)
  - Thread.join(ms)
  - LockSupport.parkNanos(ns)

6.2 sleep() 으로 진입

Thread.sleep(1000);   // RUNNABLE → TIMED_WAITING
// 1초 대기
// 시간 경과 시 RUNNABLE 복귀

// 주의: sleep 은 락 반납 X (wait 와 다름)

6.3 WAITING vs TIMED_WAITING

WAITING vs TIMED_WAITING:

WAITING (무한):
  - wait()
  - join()
  - park()
  - 시간 제한 X

TIMED_WAITING (시간):
  - wait(ms)
  - sleep(ms)
  - join(ms)
  - parkNanos(ns)
  - 시간 경과 시 자동 깨어남

핵심:
  - 시간 제한 유무

6.4 sleep() vs wait()

sleep() vs wait() — 중요 차이:

sleep(ms):
  - TIMED_WAITING
  - 락 반납 X (보유 유지)
  - Thread 의 static 메서드
  - synchronized 불필요

wait(ms):
  - TIMED_WAITING
  - 락 반납 O
  - Object 의 메서드
  - synchronized 안에서만

핵심:
  - sleep: 락 유지
  - wait: 락 반납

6.5 시각화

TIMED_WAITING:

sleep(1000):
  RUNNABLE → TIMED_WAITING
    [1초 대기]
  → RUNNABLE (자동, 시간 경과)

wait(1000):
  RUNNABLE → TIMED_WAITING (락 반납)
    [1초 또는 notify]
  → RUNNABLE (락 재획득)

6.6 ILIC 의 맥락

public class TimedWaitingExample {
    
    // sleep — 폴링 간격
    public void pollWithSleep() throws InterruptedException {
        while (!isReady()) {
            Thread.sleep(100);   // TIMED_WAITING (100ms)
            // 락 반납 X
        }
    }
    
    // wait(ms) — 타임아웃 대기
    public Shipment consumeWithTimeout(long timeoutMs) throws InterruptedException {
        synchronized (lock) {
            long deadline = System.currentTimeMillis() + timeoutMs;
            while (queue.isEmpty()) {
                long remaining = deadline - System.currentTimeMillis();
                if (remaining <= 0) return null;   // 타임아웃
                lock.wait(remaining);   // TIMED_WAITING (락 반납)
            }
            return queue.poll();
        }
    }
    
    // join(ms) — 제한 대기
    public void waitForWorkerWithTimeout(Thread worker) throws InterruptedException {
        worker.join(5000);   // TIMED_WAITING (최대 5초)
        if (worker.isAlive()) {
            log.warn("Worker still running after 5s");
        }
    }
}

6.7 자기 점검 답변

TIMED_WAITING은?

:
1. 정의:

  • 시간 제한 대기
  • 시간 경과 시 깨어남
  1. 진입:

    • sleep(ms)
    • wait(ms)
    • join(ms)
    • parkNanos
  2. vs WAITING:

    • 시간 제한 유무
  3. sleep vs wait:

    • sleep: 락 유지
    • wait: 락 반납

7️⃣ TERMINATED와 상태 전이

7.1 TERMINATED 의 정의

TERMINATED:

  스레드의 run() 메서드가 종료된 상태.
  스레드 생애의 끝.

진입:
  - run() 정상 종료
  - run() 예외로 종료

특징:
  - 최종 상태
  - 재시작 불가
  - start() 다시 호출 시 예외

7.2 종료 방법

// 정상 종료
Thread t = new Thread(() -> {
    doWork();
    // run 종료 → TERMINATED
});

// 예외 종료
Thread t2 = new Thread(() -> {
    throw new RuntimeException();
    // 예외로 종료 → TERMINATED
});

7.3 재시작 불가

Thread t = new Thread(() -> doWork());
t.start();   // RUNNABLE
t.join();    // TERMINATED 대기

// 재시작 시도
t.start();   // ❌ IllegalThreadStateException
// TERMINATED 스레드는 재시작 불가

7.4 전체 상태 전이

전체 전이:

NEW
  ↓ start()
RUNNABLE ←──────────────────┐
  ↓ synchronized (락 없음)    │ 락 획득
BLOCKED ────────────────────┤
  ↓ (RUNNABLE)               │
RUNNABLE ←──────────────────┤
  ↓ wait()/join()            │ notify/종료
WAITING ────────────────────┤
  ↓ (RUNNABLE)               │
RUNNABLE ←──────────────────┤
  ↓ sleep()/wait(ms)         │ 시간 경과/notify
TIMED_WAITING ──────────────┘
  ↓ run 종료
TERMINATED (최종)

7.5 상태 전이 표

FromTo트리거
NEWRUNNABLEstart()
RUNNABLEBLOCKEDsynchronized (락 없음)
RUNNABLEWAITINGwait(), join()
RUNNABLETIMED_WAITINGsleep(ms), wait(ms)
BLOCKEDRUNNABLE락 획득
WAITINGRUNNABLEnotify, 종료
TIMED_WAITINGRUNNABLE시간 경과, notify
RUNNABLETERMINATEDrun 종료

7.6 ILIC 의 맥락

public class ThreadLifecycleComplete {
    
    public void fullLifecycle() throws InterruptedException {
        Thread worker = new Thread(() -> {
            try {
                // RUNNABLE
                processData();
                
                Thread.sleep(100);   // TIMED_WAITING
                
                synchronized (lock) {   // BLOCKED 가능
                    lock.wait(1000);    // TIMED_WAITING (락 반납)
                }
                
                // 작업 완료 → TERMINATED
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });
        
        log.info("Before start: {}", worker.getState());   // NEW
        worker.start();
        log.info("After start: {}", worker.getState());    // RUNNABLE
        
        worker.join();   // TERMINATED 대기
        log.info("After join: {}", worker.getState());     // TERMINATED
        
        // worker.start();   // ❌ 재시작 불가
    }
    
    private final Object lock = new Object();
    private void processData() { }
}

7.7 자기 점검 답변

TERMINATED와 상태 전이는?

:
1. TERMINATED:

  • run 종료
  • 최종 상태
  • 재시작 불가
  1. 종료:

    • 정상 또는 예외
  2. 재시작:

    • start() 다시 → 예외
  3. 전이:

    • NEW → RUNNABLE → (BLOCKED/WAITING/TIMED_WAITING) → RUNNABLE → TERMINATED

8️⃣ getState()와 RUNNING

8.1 RUNNING 상태가 없다

자바에는 RUNNING 상태가 없다:

  Thread.State enum:
    NEW, RUNNABLE, BLOCKED,
    WAITING, TIMED_WAITING, TERMINATED

  RUNNING 은 없음!
  - 실행 중도 RUNNABLE
  - 실행 가능도 RUNNABLE

8.2 왜 RUNNING 이 없나

RUNNING 이 없는 이유:

  실제 CPU 실행 여부는 OS 스케줄러 소관.
  
  - 자바는 OS 스케줄링 세부 모름
  - 실행 중 ↔ 실행 가능 전이 너무 빠름
  - 추적 의미 적음

  → RUNNABLE 로 통합

8.3 getState() 반환값

Thread t = new Thread(() -> {
    while (true) {
        // CPU 집약 작업 (실제 실행 중)
    }
});
t.start();

System.out.println(t.getState());   // RUNNABLE (RUNNING 아님!)
// 실제 CPU 실행 중이어도 RUNNABLE

8.4 getState() 의 한계

getState() 의 한계:

1. RUNNING 구분 X
   - 실행 중인지 대기인지 모름

2. 스냅샷
   - 호출 순간의 상태
   - 즉시 변할 수 있음

3. I/O 대기 = RUNNABLE
   - 실제 대기여도 RUNNABLE

→ 모니터링 시 참고용
→ 정확한 진단은 jstack, 프로파일러

8.5 jstack 으로 상태 확인

# jstack — 스레드 덤프
$ jstack <pid>

# 출력 예:
"worker-1" #12 prio=5 ... RUNNABLE
  at java.net.SocketInputStream.socketRead0(Native Method)
  # RUNNABLE 이지만 socketRead = I/O 대기

"worker-2" #13 ... BLOCKED (on object monitor)
  at com.ilic.Service.process(Service.java:50)
  - waiting to lock <0x...> (a java.lang.Object)
  # BLOCKED, 락 대기

"worker-3" #14 ... WAITING (on object monitor)
  at java.lang.Object.wait(Native Method)
  # WAITING, wait 중

8.6 모니터링 도구

스레드 상태 모니터링:

1. jstack <pid>
   - 스레드 덤프
   - 상태 + 스택 트레이스
   - 데드락 감지

2. VisualVM
   - GUI
   - 실시간 스레드 상태
   - 시각화

3. JFR (Java Flight Recorder)
   - 상세 프로파일링
   - 스레드 활동

4. getState() (코드)
   - 프로그래밍 방식
   - 참고용

8.7 ILIC 의 맥락

@Component
public class ThreadStateMonitor {
    
    // getState() 활용 (참고용)
    public Map<Thread.State, Long> getThreadStateDistribution(List<Thread> threads) {
        return threads.stream()
            .collect(Collectors.groupingBy(
                Thread::getState,
                Collectors.counting()));
        // BLOCKED 가 많으면 락 경합 의심
    }
    
    // 데드락 감지 (ThreadMXBean)
    public boolean detectDeadlock() {
        ThreadMXBean bean = ManagementFactory.getThreadMXBean();
        long[] deadlocked = bean.findDeadlockedThreads();
        if (deadlocked != null) {
            log.error("Deadlock detected! {} threads", deadlocked.length);
            return true;
        }
        return false;
    }
    
    // 주의: getState() 는 RUNNING 반환 안 함
    // I/O 대기도 RUNNABLE
    // 정확한 진단은 jstack
}

8.8 자기 점검 답변

getState()가 RUNNING을 반환하는가?

:
1. 아니다:

  • RUNNING 상태 없음
  • 실행 중도 RUNNABLE
  1. 이유:

    • OS 스케줄러 소관
    • 너무 빠른 전이
    • 추적 의미 적음
  2. 한계:

    • RUNNING 구분 X
    • I/O 대기도 RUNNABLE
    • 스냅샷
  3. 진단:

    • jstack (스택 트레이스)
    • VisualVM, JFR
    • ThreadMXBean (데드락)

9️⃣ 면접 + 자기 점검

9.1 면접 단골 질문 매핑

Q핵심 답변
6가지 상태?NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED
NEW → RUNNABLE?start()
BLOCKED?synchronized 락 대기
WAITING?wait/join (무한)
TIMED_WAITING?sleep/wait(ms)
BLOCKED vs WAITING?락 반납 vs notify/종료
getState() RUNNING?아니다 (RUNNABLE)
RUNNABLE 두 의미?실행 중 + 실행 가능
sleep vs wait?락 유지 vs 반납
TERMINATED 재시작?불가 (예외)
I/O 대기 상태?RUNNABLE (자바)

9.2 자기 점검 체크리스트

6가지 상태

  • NEW, RUNNABLE
  • BLOCKED, WAITING, TIMED_WAITING
  • TERMINATED

전이

  • NEW → RUNNABLE (start)
  • RUNNABLE → BLOCKED (락)
  • RUNNABLE → WAITING (wait/join)
  • RUNNABLE → TIMED_WAITING (sleep)

차이

  • BLOCKED vs WAITING
  • WAITING vs TIMED_WAITING
  • sleep vs wait

RUNNABLE

  • 두 의미
  • I/O 대기도 RUNNABLE

getState

  • RUNNING 없음
  • jstack 진단

9.3 추가 심화 질문

Q1: BLOCKED 와 WAITING 의 깨어나는 조건 차이?

답:

  • BLOCKED: 락 반납 (다른 스레드가 synchronized 종료)
  • WAITING: notify/notifyAll (wait), 대상 종료 (join)
  • BLOCKED 는 자동 (락 경쟁), WAITING 은 명시적 신호

Q2: park 된 스레드의 상태?

답:

  • LockSupport.park(): WAITING
  • parkNanos(): TIMED_WAITING
  • BLOCKED 아님 (락 아니라 직접 대기)

Q3: 인터럽트와 상태?

답:

  • WAITING/TIMED_WAITING 중 인터럽트
  • → InterruptedException
  • → RUNNABLE 복귀
  • BLOCKED 는 인터럽트로 안 깨어남 (synchronized)

Q4: 데드락 시 상태?

답:

  • 보통 BLOCKED (서로 락 대기)
  • 또는 WAITING (wait 대기)
  • jstack 으로 "deadlock" 감지
  • ThreadMXBean.findDeadlockedThreads()

Q5: Virtual Thread 의 상태?

답:

  • 같은 Thread.State 사용
  • 단, I/O 블로킹 시 OS 스레드 양보
  • 캐리어 스레드와 마운트/언마운트
  • 상태 추적은 유사

🎯 핵심 요약 — 3줄 정리

1. 6가지 상태

  • NEW → RUNNABLE → TERMINATED
  • 중간: BLOCKED, WAITING, TIMED_WAITING

2. 핵심 차이

  • BLOCKED: 락 대기 (락 반납 시 깨어남)
  • WAITING: wait/join (notify/종료 시)
  • TIMED_WAITING: sleep/wait(ms) (시간)

3. RUNNABLE과 getState

  • RUNNING 없음 (RUNNABLE 포함)
  • I/O 대기도 RUNNABLE
  • 진단: jstack

📚 다음으로...

Unit 3.2 — Thread 클래스 상속

이번 Unit에서 스레드 상태를 봤다면, 다음은 Thread 클래스 상속으로 스레드 만들기.

  • Thread 상속 + run() 오버라이드
  • start() vs run()
  • start() 두 번 호출

Phase 3 진행 상황

🚀 Phase 3 — 스레드 만들고 다루기
  ✅ Unit 3.1 스레드 상태 다이어그램 ← 여기
  ⏭ Unit 3.2 Thread 클래스 상속
  ⏭ Unit 3.3 Runnable 인터페이스
  ⏭ Unit 3.4 데몬 스레드
  ⏭ Unit 3.5 join()

4주차 누적 진행

✅ Phase 1 — 동시성의 기초 (4 Unit)
✅ Phase 2 — 4분면 매트릭스 (3 Unit)
🚀 Phase 3 — 스레드 다루기 (1/5 진행)

총: 8/35 Unit
profile
Software Developer

0개의 댓글