Java 스레드(Thread) 덤프 생성 방법과 상태(State) 분석 가이드

서버를 운영하다 보면 OutOfMemoryError처럼 명확한 에러 로그를 남기며 서버가 죽는 경우도 있지만, 에러도 없이 CPU 사용률이 100%로 치솟거나 사용자의 요청에 서버가 먹통(Timeout)이 되는 현상이 더 자주 발생합니다. 이럴 때 개발자가 서버의 내부 상황을 들여다보기 위해 촬영하는 ‘X-ray 사진’이 바로 스레드 덤프(Thread Dump)입니다.

엔터프라이즈 환경에서 성능 튜닝과 장애 분석을 마스터하려면 스레드 덤프를 추출하고 해석하는 능력이 필수적입니다. 이번 글에서는 스레드 덤프가 무엇인지, 운영 서버에서 이를 어떻게 생성하고 스레드의 상태(State)를 어떻게 분석해야 하는지 완벽한 가이드를 제공합니다.

1. 스레드 덤프(Thread Dump)란 무엇인가?

스레드 덤프는 특정 시점에 JVM(Java Virtual Machine) 내에서 동작하고 있는 모든 스레드(Thread)의 상태와 콜 스택(Call Stack) 정보를 기록한 스냅샷입니다.

애플리케이션에 트래픽이 몰려 병목 현상이 발생했을 때 스레드 덤프를 확인해 보면, 어떤 스레드가 외부 API의 응답을 기다리며 멈춰 있는지, 어떤 스레드들이 데이터베이스 커넥션을 얻기 위해 줄을 서고(대기) 있는지, 또 특정 스레드가 어떤 메서드 라인에서 무한 루프에 빠져있는지 정확하게 추적할 수 있습니다.

2. 운영 서버에서 스레드 덤프를 생성하는 3가지 방법

리눅스(Linux) 환경의 운영 서버에서 스레드 덤프를 텍스트 파일로 추출하는 대표적인 방법 3가지는 다음과 같습니다. (먼저 jps 명령어나 ps -ef | grep java를 통해 Java 프로세스의 PID 번호를 알아야 합니다.)

  • jcmd 유틸리티 사용 (권장): Java 8 이후부터 가장 권장되는 통합 진단 도구입니다. jcmd <PID> Thread.print > threaddump.txt
  • jstack 유틸리티 사용: 전통적으로 가장 많이 쓰이는 스레드 분석 도구입니다. jstack -l <PID> > threaddump.txt
  • OS 시그널(kill -3) 활용: jstack이나 jcmd를 사용할 수 없는 제한된 환경에서 유용합니다. 프로세스를 죽이지 않고 덤프만 표준 출력(Standard Out)으로 내보냅니다. kill -3 <PID>

💡 실무 팁: 스레드의 흐름을 정확히 분석하기 위해서는 스레드 덤프를 1회만 생성해서는 안 됩니다. 반드시 3~5초 간격으로 3번 이상 연속으로 추출하여, 각 덤프 파일 간에 스레드의 상태가 어떻게 변하고 있는지(진행 중인지, 계속 멈춰 있는지)를 비교 분석해야 합니다.

3. 스레드의 5가지 주요 상태(State) 완벽 해부

추출된 스레드 덤프 파일을 열어보면 각 스레드의 이름 옆에 java.lang.Thread.State: [상태명] 형태로 현재 상태가 기록되어 있습니다. 이 상태들을 이해하는 것이 분석의 핵심입니다.

  • NEW: 스레드 객체가 생성만 되고 아직 start() 메서드가 호출되지 않은 상태입니다. (덤프에 잘 나타나지 않습니다.)
  • RUNNABLE: 스레드가 현재 CPU 자원을 할당받아 실행 중이거나, 언제든 실행될 수 있도록 준비 대기 중인 상태입니다. 이 상태가 많다고 무조건 좋은 것은 아니며, CPU 100% 현상 시 특정 스레드가 무한 루프를 돌며 계속 RUNNABLE 상태에 머물러 있지 않은지 의심해 보아야 합니다.
  • BLOCKED: 스레드가 synchronized 블록이나 메서드에 진입하기 위해 다른 스레드가 사용 중인 락(Lock)이 풀리기를 기다리는 상태입니다. 이 상태의 스레드가 급증한다면 시스템에 심각한 병목(동기화 경합)이 발생했다는 징후입니다.
  • WAITING: 다른 스레드가 특정 작업(notify(), notifyAll())을 수행해 주기를 시간제한 없이 무한정 기다리는 상태입니다. 스레드 풀(Thread Pool)에서 작업을 대기하는 유휴 스레드들이 주로 이 상태를 가집니다.
  • TIMED_WAITING: WAITING과 같지만 지정된 시간(Timeout) 동안만 대기하는 상태입니다. 외부 API를 호출하거나 DB 쿼리를 던지고 응답을 기다리는 스레드(Thread.sleep(), Object.wait(timeout) 등)에서 가장 흔하게 관찰됩니다.

결론: 병목을 찾는 가장 확실한 X-ray

스레드 덤프 분석은 직관적이지 않은 수많은 텍스트 더미 속에서 패턴을 찾아내는 고도의 기술입니다. 하지만 RUNNABLE, BLOCKED, TIMED_WAITING 이 세 가지 핵심 상태의 의미만 정확히 알고 있어도, 대부분의 서버 지연 현상 원인을 찾아낼 수 있습니다.

이번 글을 통해 스레드 덤프의 기초를 다졌으니, 다음 포스팅에서는 멀티 스레드 프로그래밍 최악의 악몽이자 서버를 완전히 멈추게 만드는 ‘교착 상태(Deadlock) 발생 원인과 스레드 덤프를 통한 해결 전략’에 대해 구체적인 사례와 함께 깊이 있게 파헤쳐 보겠습니다.

댓글 남기기