본문 바로가기
Language/Java

[JAVA] Thread 생명 주기 완벽 가이드 : NEW에서 TERMINATED까지

by Papa Martino V 2026. 1. 21.
728x90

쓰레드의 상태(NEW, RUNNABLE, BLOCKED 등)
쓰레드의 상태(NEW, RUNNABLE, BLOCKED 등)

 

자바(Java) 멀티쓰레딩 환경에서 성능 최적화와 안정적인 애플리케이션 운영을 위해 가장 기본이 되면서도 중요한 개념은 바로 쓰레드의 상태(Thread States)를 이해하는 것입니다. 쓰레드가 생성되고, 실행되며, 때로는 대기하거나 종료되는 전체 과정을 명확히 파악해야만 '데드락(Deadlock)'이나 '레이스 컨디션(Race Condition)' 같은 복잡한 동시성 문제를 해결할 수 있습니다. 이 글에서는 JDK의 Thread.State 열거형(Enum)을 바탕으로 자바 쓰레드의 6가지 상태를 심도 있게 분석하고, 각 상태 간의 전이 과정과 실무적인 관점에서의 주의사항을 정리해 드립니다.

1. 자바 쓰레드의 6가지 핵심 상태

자바 공식 문서에 정의된 java.lang.Thread.State에 따르면, 쓰레드는 특정 시점에 반드시 다음 중 하나의 상태에 놓이게 됩니다.

상태 (State) 설명 (Description) 주요 특징
NEW 쓰레드 객체가 생성되었으나 아직 시작되지 않은 상태 start() 메서드 호출 전
RUNNABLE 실행 중이거나 실행 준비가 완료되어 CPU 할당을 기다리는 상태 JVM 내에서 실행 중인 상태
BLOCKED 모니터 락(Monitor Lock)을 획득하기 위해 대기하는 상태 synchronized 블록/메서드 진입 대기
WAITING 다른 쓰레드가 특정 작업을 수행하기를 무기한 기다리는 상태 wait(), join() 호출 시
TIMED_WAITING 지정한 시간 동안 다른 쓰레드의 작업을 기다리는 상태 sleep(ms), wait(ms) 호출 시
TERMINATED 실행이 완료되어 종료된 상태 run() 메서드 종료 후 재시작 불가

2. 상태별 상세 분석 및 전이 과정

① NEW (새로운 상태)

쓰레드 클래스를 인스턴스화한 직후입니다. 메모리상에 객체는 존재하지만, 아직 독립적인 실행 흐름으로 동작하지는 않습니다. 오직 start() 메서드를 통해서만 다음 단계로 넘어갈 수 있습니다.

② RUNNABLE (실행 가능 상태)

자바의 RUNNABLE은 독특합니다. OS 레벨에서의 'Running(실행 중)'과 'Ready(준비 완료)' 상태를 모두 포함합니다. 즉, 현재 CPU를 점유하여 코드를 실행 중일 수도 있고, OS의 스케줄러에 의해 선택되기를 기다리고 있을 수도 있습니다.

③ BLOCKED (차단 상태)

주로 동기화(Synchronization)와 관련이 있습니다. 특정 객체의 락을 다른 쓰레드가 이미 소유하고 있을 때, 그 락을 얻기 위해 줄을 서 있는 상태입니다. 락이 해제되면 다시 RUNNABLE 상태로 돌아갑니다.

④ WAITING & TIMED_WAITING (대기 상태)

쓰레드가 스스로 실행 권한을 포기하고 기다리는 상태입니다.

  • WAITING: Object.wait()Thread.join()처럼 기약 없이 기다리는 경우입니다. 외부의 notify() 호출이 있어야 깨어납니다.
  • TIMED_WAITING: Thread.sleep(1000)처럼 정해진 시간이 지나면 자동으로 RUNNABLE 상태로 복귀합니다.

⑤ TERMINATED (종료 상태)

run() 메서드의 실행이 끝나거나 예외가 발생하여 쓰레드가 종료된 상태입니다. 한 번 종료된 쓰레드 객체는 다시 start()를 호출할 수 없으며, 호출 시 IllegalThreadStateException이 발생합니다.


3. 실무 예제 (Sample Example)

다음 코드는 쓰레드를 생성하고 실행하면서 각 단계의 상태 변화를 콘솔에 출력하는 예시입니다.


public class ThreadStateDemo {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            try {
                // TIMED_WAITING 상태 유도
                Thread.sleep(1000);
                
                synchronized (ThreadStateDemo.class) {
                    // 내부 로직 수행
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        System.out.println("1. 생성 직후 상태: " + thread.getState()); // NEW

        thread.start();
        System.out.println("2. start() 호출 후 상태: " + thread.getState()); // RUNNABLE

        Thread.sleep(500);
        System.out.println("3. sleep 중인 상태: " + thread.getState()); // TIMED_WAITING

        thread.join();
        System.out.println("4. 종료 후 상태: " + thread.getState()); // TERMINATED
    }
}

4. 개발자를 위한 기술적 조언

애플리케이션이 갑자기 느려지거나 멈춘다면 Thread Dump를 분석해야 합니다. 이때 BLOCKED 상태의 쓰레드가 많다면 동기화 지점에서 병목이 발생하고 있는 것이고, WAITING 상태가 많다면 쓰레드 풀 설정이나 외부 리소스 응답 대기 시간을 점검해 보아야 합니다.


출처 및 참고문헌

  • Oracle Java Documentation: java.lang.Thread.State
  • Effective Java 3rd Edition (Joshua Bloch)
  • Java Concurrency in Practice (Brian Goetz)
728x90