BJ.14 OS 프로세스의 상태 및 자바 스레드 상태에 대해서

Meustar·2026년 1월 3일

출처: https://www.youtube.com/watch?v=_dzRW48NB9M

movie

📌 OS 프로세스와 자바 스레드의 상태 변화를 알아야 하는 이유는?

서버 불능 시 문제 분석 및 원인 파악에 필수적이기 때문입니다.

💡 OS 프로세스와 자바 스레드의 상태 변화는 어떻게 다른가요?

구분OS 프로세스자바 스레드
주요 상태New, Ready, Running, Waiting, TerminatedNew, Runnable, Blocked, Waiting, Timed Waiting, Terminated
Runnable 포함 범위Running, ReadyRunning, Ready, I/O 대기 등 포괄적

배경지식: 운영체제와 자바의 '상태'를 꿰뚫어 보는 법

원본 자료(OS 프로세스 상태 및 자바스레드 상태)를 100% 이해하기 위해, 영상에서 자세히 다루지 않았지만 핵심적인 맥락과 용어를 깊이 있게 살펴보겠습니다. 특히, 강의를 제공하는 이의 전문성부터 시작해 자바 동시성 제어의 근간이 되는 개념들, 그리고 실제 서버 장애 분석 기법까지 명확하게 이해하는 것이 목표입니다.

1. OS와 Java의 상태 매핑: 'RUNNABLE'의 포괄성

원본 자료에서 OS 프로세스 상태와 자바스레드 상태를 비교할 때, 자바의 RUNNABLE 상태가 OS의 Ready와 Running 상태를 모두 포괄하는 매우 광범위한 개념이라고 설명했습니다. 이 차이는 자바가상 머신(JVM)의 작동 방식에서 비롯됩니다.

가. OS 프로세스 상태 (5단계 모델)

OS 프로세스의 생애 주기는 비교적 명확하게 구분됩니다.

  • Ready (준비):CPU에서 실행될 준비가 되었으나, CPU가 이미 다른 프로세스를 실행 중이라 대기하는 상태입니다.
  • Running (실행):CPU를 할당받아 실제로 명령어(Instruction)를 실행하고 있는 상태입니다.

나. 자바 스레드 상태 (6단계 모델)

자바는 java.lang.Thread.State라는 6가지 상태를 정의합니다. 이 중 RUNNABLE 상태는 OS의 스케줄링 영역에 개입하지 않기 위해 Ready와 Running을 하나로 합친 개념입니다.

  • RUNNABLE의 의미: 스레드가 현재 CPU에서 실행 중이거나, 실행될 준비가 되어 스케줄러의 선택을 기다리고 있는 상태를 모두 포함합니다 .
  • 이유:자바는 플랫폼 독립성을 위해 내부적으로는 스레드를 관리하지만, 실제 CPU 할당과 스케줄링은 운영체제(OS) 커널에게 맡깁니다.
    • JVM은 OS에게 "이 스레드를 실행할 준비가 되었어"라고만 알려줄 뿐, OS가 언제 CPU를 줄지, 현재 실행 중인지 대기 중인지는 구분하지 않습니다.
    • 따라서 RUNNABLE 상태는 OS의 Ready와 Running 모두에 해당하며, 자바 프로그램 코드 레벨에서는 이 둘을 구별할 수 없습니다.
OS 상태Java 상태설명
Ready + RunningRUNNABLECPU를 얻을 자격이 있으며, 현재 실행 중이거나(Running) 스케줄러의 선택을 기다리는 상태(Ready)
WaitingWAITING무한정으로 다른 스레드의 특정 알림을 기다리는 상태 (wait() 호출)
I/O Wait, Lock WaitBLOCKED모니터 락(Monitor Lock)을 얻기 위해 대기하는 상태

2. 동기화의 핵심: 모니터(Monitor)와 뮤텍스(Mutex)

원본 자료에서 자바스레드 상태 중 BLOCKED와 WAITING 상태를 설명할 때 모니터 락(Monitor Lock)과 wait() 메서드가 핵심적으로 언급됩니다. 자바의 동기화가 이루어지는 바탕인 모니터 개념을 명확히 이해해야 합니다.

가. 뮤텍스(Mutex)의 역할

  • 정의:MUTual EXclusion (상호 배제)의 약자로, 오직 하나의 스레드만이 공유 자원에 접근할 수 있도록 보장하는 메커니즘입니다 .
    • 실생활 비유: 화장실 문에 달린 잠금장치. 누군가 안에 들어가면 문을 잠가 다른 사람이 들어오지 못하게 합니다.

나. 모니터(Monitor)의 역할

  • 정의: 모니터는 뮤텍스 위에 덧대어진 추가적인 구조(Superstructure)로, 동기화 기능을 제공하는 코드 덩어리입니다.
    • 자바에서는 모든 객체에 하나의 모니터가 내장되어 있으며, 이 모니터는 내부적으로 하나의 뮤텍스 락(또는 고유 락)과 조건 변수(Condition Variable)를 가집니다.
    • 자바의 synchronized 키워드는 바로 이 모니터 메커니즘을 사용합니다 .

다. 모니터와 상태 변화의 연결점

  • BLOCKED 상태: 스레드가 synchronized 블록(크리티컬 섹션)에 진입하려 할 때, 이미 다른 스레드가 모니터 락(뮤텍스)을 쥐고 있다면, 이 스레드는 락을 얻기 위해 대기하며 BLOCKED 상태로 바뀝니다 .
  • WAITING 상태: 스레드가 임계 구역 안에서 wait() 메서드를 호출하면, 본인이 쥐고 있던 모니터 락을 스스로 반환하고, 조건 변수가 충족될 때까지(즉, 다른 스레드의 notify() 또는 notifyAll() 호출을 기다리며) WAITING 상태로 빠집니다 .

3. 실전 분석: 쓰레드 덤프(Thread Dump)의 이해

원본 자료의 말미에서 '서버가 불능에 빠졌을 때' 분석 도구로 자바쓰레드 덤프가 언급됩니다. 이는 멀티스레딩 환경에서 발생한 문제를 진단하는 핵심 방법론입니다.

가. 쓰레드 덤프란?

  • 정의: 실행 중인 자바프로세스의 특정 시점 스냅샷으로, 프로세스 내 모든 스레드의 상태, 스택 트레이스(호출된 메서드 목록), 그리고 어떤 락을 보유하거나 기다리고 있는지 등의 정보를 담고 있는 파일입니다 .
  • 용도: 서버가 갑자기 느려지거나 멈추는(Hang) 현상이 발생했을 때, 병목 현상(Bottleneck)의 원인이나 데드락(Deadlock)을 분석하는 데 사용됩니다.

나. 쓰레드 덤프 분석으로 알 수 있는 것

쓰레드 덤프 분석의 핵심은 오랫동안 대기하거나 블록된 스레드를 찾는 것입니다.

  • 데드락(Deadlock) 탐지: 여러 스레드가 서로 상대방이 쥐고 있는 락을 기다리며 무한 대기하는 상황을 파악합니다.
    • 덤프에서 대부분의 스레드가 BLOCKED나 WAITING 상태로 특정 락을 기다리는 패턴을 통해 데드락을 식별할 수 있습니다 .
  • 병목 현상(Bottleneck) 식별:CPU 사용량이 비정상적으로 높다면 RUNNABLE스레드에 집중하여, 어떤 코드 블록이 장시간 CPU를 점유하고 있는지 확인합니다.
    • 반대로 성능이 비정상적으로 낮다면 BLOCKED스레드를 확인하여, 어떤 락(Lock) 때문에 작업이 지연되고 있는지 파악합니다.

다. 효율적인 분석 기법

효율적인 문제 진단을 위해 단일 스냅샷이 아닌, 10초 간격으로 최소 3개 이상의 덤프를 연속적으로 수집하여 스레드의 상태 변화 추이를 비교하는 것이 일반적인 권장 사항입니다 .

  • Tip:jps 명령어로 자바프로세스 ID(PID)를 확인하고, jstack -l [PID] > dump.txt 명령어를 사용하여 덤프 파일을 생성할 수 있습니다.

1. 운영체제(OS) 프로세스 상태 변화 흐름

1.1. 프로세스 상태의 시작과 준비 (New, Ready)

  1. New (생성) 상태: 프로세스가 처음 생성되면 'New' 상태에서 시작한다.
  2. Ready (준비) 상태로의 전이:
    1. 'New' 상태에서 기다리다가 롱텀 스케줄러의 허락을 받으면 'Ready' 상태로 바뀌어 CPU에서 실행될 준비를 한다.
    2. 오늘날 일반적인 컴퓨터(부품 사용)에서는 롱텀 스케줄러가 없으므로, 프로세스 생성 시 바로 'Ready' 상태로 간다고 이해할 수 있다.
    3. 롱텀 스케줄러가 필요한 상황은 리얼타임 OS 같은 특수한 운영체제에 해당한다.
  3. Ready 상태의 의미: CPU에서 실행되기 위해 기다리는 상태를 의미하며, 이는 CPU에서 이미 다른 프로세스가 실행되고 있기 때문이다.

1.2. 실행 및 대기 상태의 순환 (Running, Waiting)

  1. Running (실행) 상태로의 전이:
    1. 'Ready' 상태에서 기다리다가 스케줄러에 의해 자신의 차례가 되면 'Running' 상태로 바뀌어 CPU에서 실행된다.
  2. Ready 상태로의 복귀 (멀티태스킹):
    1. 오늘날 대부분의 컴퓨터는 멀티태스킹 방식이므로, 자신에게 할당된 타임 슬라이스를 모두 사용하게 되면 다시 'Ready' 상태로 돌아와 기다려야 한다.
  3. Waiting (대기) 상태로의 전이:
    1. 'Running' 상태에서 실행 중 I/O 작업을 하러 가야 하거나, 크리티컬 섹션에 진입하려는데 이미 다른 프로세스가 점유하고 있어 기다려야 하는 상황이 발생하면 'Waiting' 상태로 빠지게 된다.
    2. 이 상태에서는 I/O 작업이 완료되거나 크리티컬 섹션에 들어갈 수 있을 때까지 기다린다.
  4. Ready 상태로의 복귀 (대기 완료):
    1. I/O 작업이 완료되거나 크리티컬 섹션에 들어갈 수 있게 되면 바로 'Running' 상태가 되는 것이 아니라 다시 'Ready' 상태로 바뀐다.
    2. 이는 CPU에 이미 다른 프로세스가 실행 중이므로, CPU에 들어갈 준비를 해야 하기 때문이다.
    3. 'Ready' 상태에서 기다리다가 스케줄러가 차례를 알려주면 다시 CPU로 가서 실행('Running')을 하게 된다.

1.3. 프로세스의 종료 (Terminate)

  1. Terminate (종료) 상태로의 전이:

    1. 프로세스가 마무리를 해야 하는 상황이 오면, 바로 종료되는 것이 아니라 일단 'Running' 상태로 바꾼 뒤 CPU에서 마무리 작업을 실행한다.
    2. 마무리 작업이 실행되고 프로세스가 종료되면 최종적으로 'Terminate' 상태로 바뀌게 된다.
  2. 스레드 상태와의 관계:

    1. 스레드는 메모리를 공유하는 프로세스이므로, OS 스레드의 상태 변화는 위에서 설명한 프로세스의 상태 변화와 거의 동일하다고 볼 수 있다.
  3. 용어의 차이:

    1. 용어나 표기(PK)는 운영체제마다 조금씩 다를 수 있다.
    OS 프로세스 상태역할 (비유)다음 예상되는 상태
    New새로 태어남 (선수 등록)Ready
    ReadyCPU 사용을 대기 (트랙 밖 대기)Running
    RunningCPU 사용 중 (트랙 위 달리기)Ready, Waiting, Terminate
    Waiting외부 자원/I/O 대기 (화장실 사용 대기)Ready
    Terminate종료됨 (경기 끝)-

2. 자바 스레드의 6가지 상태 및 특징

자바 스레드의 상태는 운영체제의 프로세스 상태 관리 방식과 다를 수 있으며, 특히 백엔드 자바는 멀티 스레딩 환경에서 많이 구현되므로 자바 스레드 상태를 이해하는 것이 중요하다.

  1. 자바 스레드의 6가지 상태: 자바 스레드의 상태 종류는 총 6가지이다.
    1. NEW: 자바 스레드가 아직 시작하지 않은 상태이다.
    2. TERMINATED: 실행을 시작하고 종료된 상태이다.
    3. WAITING (대기): 어떤 스레드가 다른 스레드를 기다리는 상태를 의미한다.
      1. 이 상태가 되는 조건은 자바 공식 문서에서 코드 레벨로 설명하고 있다.
      2. Object 클래스의 wait() 메서드 호출: Object 클래스는 모든 클래스의 조상이며, 인스턴스마다 모니터(뮤텍스 락과 컨디션 변수)를 가지고 있는데, 이 wait() 메서드를 호출하면 스레드는 'WAITING' 상태로 빠진다.
      3. Thread 클래스의 join() 메서드 호출: 이 메서드를 호출하게 되면 해당 스레드들은 'WAITING' 상태로 바뀌게 된다.
    4. TIMED_WAITING (시간 제한 대기): 'WAITING' 상태와 동일하지만, 제한 시간을 두고 다른 스레드를 기다리는 상태이다.
      1. 정해진 시간만큼만 다른 스레드의 이벤트나 알람(notify)을 기다리겠다는 상태이다.
      2. 이 상태에 빠지도록 만드는 메서드는 다음과 같다.
      3. Object 클래스의 wait() 메서드 호출 시 타임아웃(제한 시간)을 파라미터로 전달하는 경우
      4. Thread 클래스의 join() 메서드 호출 시 타임아웃 파라미터를 전달하는 경우
      5. Thread 클래스의 sleep() 메서드를 호출하는 경우
    5. BLOCKED (블록): 모니터 락을 얻기 위해 기다리는 상태이다.
      1. 구체적으로는 크리티컬 섹션으로 들어가려고 모니터 락을 얻기 위해 기다리는 상태이다.
    6. RUNNABLE (실행 가능): 자바 스레드가 실행 중인 상태를 의미하는 포괄적인 개념이다.
      1. 실제로 CPU 상에서 실행되는 'Running' 상태를 포괄한다.
      2. 다른 리소스를 기다리는 상태도 포괄한다.
      3. CPU에서 실행되려고 기다리는 상태(OS의 Ready)도 이 상태이다.
      4. I/O 작업을 해놓고 그 결과를 기다리는 상태(OS의 Waiting)도 이 상태이다.
      5. 따라서 자바 스레드의 'RUNNABLE' 상태는 운영체제의 'Running' 상태에 비해 훨씬 더 포괄적인 개념이다.

3. 자바 스레드 상태 변화 예시: wait()와 notifyAll()을 통한 전이

3.1. 초기 설정 및 컨슈머 스레드의 대기 (NEW → RUNNABLE → WAITING)

  1. 예시 환경: 앞선 영상에서 사용했던 모니터 관련 예시를 활용하며, 아이템을 넣고 뺄 수 있는 BoundedBuffer 클래스(버퍼)와 이를 활용하는 Main 클래스 코드를 사용한다.
  2. 크리티컬 섹션 정의:
    1. BoundedBuffer 클래스에는 synchronized 키워드가 붙은 produce 메서드와 consume 메서드가 있다.
    2. synchronized 키워드가 붙은 메서드나 블록은 한 번에 하나의 스레드만 실행될 수 있으며, 해당 스레드는 객체가 가진 모니터(뮤텍스 락)를 쥐고 들어간다.
    3. 따라서 이 synchronized로 보호받는 부분은 크리티컬 섹션이다.
  3. 객체 및 스레드 생성:
    1. BoundedBuffer 타입의 인스턴스를 생성하면, 이 객체는 내부적으로 모니터 락과 컨디션 변수를 가진 모니터를 소유하게 된다.
    2. 아이템을 뽑아내는 Consumer 스레드와 아이템을 밀어 넣는 Producer 스레드 2개를 정의하고 동시에 실행한다.
  4. 컨슈머 스레드의 상태 변화 (NEW → RUNNABLE):
    1. Consumer 스레드가 처음 만들어지면 상태는 NEW이다.
    2. start()를 통해 실행을 시작하면 상태는 RUNNABLE이 된다.
  5. 컨슈머 스레드의 WAITING 진입:
    1. Consumer 스레드는 consume 메서드를 실행하며 synchronized 블록(크리티컬 섹션)으로 진입을 시도한다.
    2. 버퍼의 모니터 락을 취득하고 크리티컬 섹션 안으로 들어간다. (최초 진입이므로 락 취득 성공)
    3. 버퍼가 비어있는지 확인(버퍼 카운터 0)하고, 비어있으므로 wait() 메서드를 호출한다.
    4. wait() 호출 순간, Consumer 스레드의 상태는 WAITING이 되며, 누군가 깨워줄 때까지 잠든다.
    5. wait()를 호출하는 순간, Consumer 스레드는 본인이 쥐고 있던 모니터 락을 반환한다.

3.2. 프로듀서의 실행과 컨슈머의 BLOCKED 상태 전이 (WAITING → BLOCKED)

  1. 프로듀서 스레드의 실행:
    1. Producer 스레드가 시작하여 produce 메서드를 호출한다.
    2. Consumer가 락을 반환했기 때문에, Producer는 모니터 락을 성공적으로 확보하고 produce 메서드 안으로 진입한다.
  2. 아이템 생산 및 알림:
    1. Producer는 버퍼가 다 차지 않았으므로 아이템(100)을 버퍼에 채워 넣는다.
    2. notifyAll()을 호출하여 잠들고 있던 Consumer 스레드를 깨운다.
  3. BLOCKED 상태로의 전이:
    1. Consumer 스레드는 깨어나지만, 바로 실행 상태가 되는 것이 아니다.
    2. 자바는 시그널을 컨티뉴 방식으로 동작하므로, Producer는 notifyAll()을 호출한 후에도 크리티컬 섹션 안에서 모니터 락을 유지하고 계속 활동한다.
    3. Consumer 스레드 입장에서는 깨어났지만, 아직 모니터 락을 쥐고 있지 않은 상태이다.
    4. 따라서 Consumer의 상태는 WAITING에서 BLOCKED 상태로 바뀌게 된다. (준비 상태(RUNNABLE)로 바뀌는 것이 아님)
    5. 이 상태는 모니터 락을 취득하기 위해 기다리는 상태를 의미한다.

3.3. 컨슈머의 재실행 및 종료 (BLOCKED → RUNNABLE → TERMINATED)

  1. 모니터 락 반환:
    1. Producer 스레드는 실행을 마치고 produce 메서드를 탈출하며 쥐고 있던 모니터 락을 반환한다.
  2. RUNNABLE 상태로의 복귀:
    1. 모니터 락을 기다리고 있던 Consumer 스레드가 이어서 시작할 수 있게 된다.
    2. Consumer 스레드의 상태는 RUNNABLE로 바뀌게 된다.
  3. 아이템 소비 및 종료:
    1. Consumer는 깨어났기 때문에 버퍼에서 아이템(100)을 가지고 오고, 혹시 다른 스레드가 기다릴까 싶어 다시 깨우는(notify) 작업을 한 뒤 synchronized 블록을 탈출한다.
    2. Consumer는 synchronized 블록을 빠져나온 뒤 컨슈머 메서드를 종료한다.
    3. 컨슈머 메서드가 종료되면 Consumer 스레드의 상태는 최종적으로 TERMINATED가 된다.

자바 스레드 상태OS 프로세스 상태와 비슷한 의미설명
NEWNew스레드가 아직 시작되지 않은 상태예요 .
RUNNABLEReady + Running실행 중이거나 실행 대기 중인 상태를 모두 포괄해요 .
BLOCKEDWaiting (일부)모니터 락을 얻으려고 기다리는 상태예요 .
WAITINGWaiting (무기한)다른 스레드를 무기한 기다리는 상태예요 .
TIMED_WAITINGWaiting (시간 제한)제한 시간을 두고 다른 스레드를 기다리는 상태예요 .
TERMINATEDTerminated실행을 마치고 종료된 상태예요 .

4. 자바 스레드 덤프 분석의 중요성

  1. 스레드 덤프의 정의:
    1. 스레드 덤프는 실행 중인 자바 프로세스의 현재 상태를 담은 스냅샷이다.
    2. 이를 통해 프로세스의 상태 정보와 스레드 정보를 알 수 있다.
  2. 스레드 덤프의 활용:
    1. 현업에서 자바로 개발된 서버(예: 아파치 서버) 운영 중 스레드를 거의 다 사용해 새로운 AP 요청에 응답하지 못하는 상황이 발생할 때 사용된다.
    2. 서버 터미널로 접근하여 해당 자바 인스턴스의 스레드 덤프를 떠서 분석한다.
  3. 문제 진단:
    1. 스레드 덤프를 분석하면 어디가 문제인지 스레드 상태를 보고 알 수 있다.
    2. 만약 데드락이 발생했다면, 대부분의 스레드가 BLOCKED이거나 WAITING 상태인 패턴을 통해 병목 현상이나 스레드 고갈 여부를 분석할 수 있다.
  4. 개발자의 역할:
    1. 자바 개발자는 스레드 덤프를 잘 사용할 수 있어야 하며, 이를 통해 서비스 문제 발생 시 원인을 파악하고 재발 방지 대책을 마련할 수 있다.
profile
유튜브 기술 영상을 보면서 잘 이해하기 위해... Lilys AI를 활용해 배경지식, 영상 전체 요약 및 핵심 내용 설명들을 블로깅 합니다. 작성한 내용들에 대해서 언제고 다시 "내가" 찾아 볼 수 있도록 기록으로 남깁니다!

0개의 댓글