프로세스와 스레드의 차이

한 줄 정의

프로세스는 실행 중인 프로그램의 독립적인 메모리 단위이고, 스레드는 프로세스 내에서 실행 흐름을 나누는 경량 단위다.

실무에서 왜 중요한가

프로세스와 스레드를 이해하지 못하면 다음 문제가 생긴다.

  • 서버의 스레드 수를 근거 없이 설정해서 CPU 사용률이 비정상적이다.
  • 멀티스레드에서 공유 자원 접근 시 동시성 문제가 발생한다.
  • 스레드 덤프를 떠도 내용을 해석하지 못한다.
  • 스레드 풀 고갈의 원인을 파악하지 못한다.

프로세스 (Process)

프로세스는 OS로부터 독립된 메모리 공간을 할당받아 실행되는 단위다.

┌─────────────────────────┐
│        Process A        │
│  ┌─────┬──────┬──────┐  │
│  │Code │ Data │ Heap │  │
│  └─────┴──────┴──────┘  │
│  ┌──────────────────┐   │
│  │   Stack (Main)   │   │
│  └──────────────────┘   │
└─────────────────────────┘
         ↕ IPC (Inter-Process Communication)
┌─────────────────────────┐
│        Process B        │  ← 별도 메모리 공간
└─────────────────────────┘
  • 프로세스 간에는 메모리를 공유하지 않는다.
  • 프로세스 간 통신(IPC)은 파이프, 소켓, 공유 메모리 등을 사용한다.
  • 한 프로세스가 죽어도 다른 프로세스에 영향이 없다.

스레드 (Thread)

스레드는 프로세스 내에서 Code, Data, Heap을 공유하면서 각자의 Stack만 독립적으로 가진다.

┌─────────────────────────────────┐
│            Process              │
│  ┌─────┬──────┬──────────────┐  │
│  │Code │ Data │     Heap     │  │  ← 스레드 간 공유
│  └─────┴──────┴──────────────┘  │
│  ┌────────┐ ┌────────┐ ┌────────┐
│  │Stack-1 │ │Stack-2 │ │Stack-3 │  ← 스레드별 독립
│  │Thread-1│ │Thread-2│ │Thread-3│
│  └────────┘ └────────┘ └────────┘
└─────────────────────────────────┘

프로세스 vs 스레드

구분프로세스스레드
메모리독립코드/데이터/힙 공유
생성 비용높음낮음
통신IPC 필요공유 메모리로 직접
안전성한 프로세스 죽어도 다른 프로세스 안전한 스레드 오류가 프로세스 전체에 영향
컨텍스트 스위칭비용 높음비용 낮음

Java에서의 스레드

스레드 풀 (Thread Pool)

스레드를 매번 생성/소멸하면 비용이 크다. 스레드 풀은 미리 스레드를 만들어두고 작업을 큐에 넣어 재사용한다.

// Tomcat 스레드 풀 설정
server:
  tomcat:
    threads:
      max: 200        # 최대 스레드 수
      min-spare: 10   # 최소 유지 스레드
    max-connections: 8192
    accept-count: 100  # 대기 큐 크기
요청 → Accept Queue → Thread Pool에서 스레드 할당 → 처리 → 반환

Thread Pool (max=200):
[Thread-1: 처리 중] [Thread-2: 처리 중] [Thread-3: 유휴] ... [Thread-200]

모든 스레드가 처리 중이면 → Accept Queue에서 대기
Accept Queue도 가득 차면 → 요청 거부 (Connection Refused)

스레드 풀 사이즈 결정

  • CPU 바운드 작업: 코어 수 + 1 (계산 위주)
  • I/O 바운드 작업: 코어 수 × (1 + 대기시간/처리시간) (DB 조회, API 호출 위주)

대부분의 웹 서버는 I/O 바운드이므로 코어 수보다 많은 스레드를 설정한다. Tomcat 기본값 200은 대부분의 상황에서 적절한 시작점이다.

스레드 덤프

# JVM 스레드 덤프 출력
jstack <PID>
kill -3 <PID>
"http-nio-8080-exec-5" #35 daemon prio=5 os_prio=0 tid=0x00007f
   java.lang.Thread.State: WAITING (parking)
    at sun.misc.Unsafe.park(Native Method)
    at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
    at com.zaxxer.hikari.pool.HikariPool.getConnection(HikariPool.java:162)
스레드 상태의미주의 사항
RUNNABLE실행 중 또는 실행 대기정상
WAITING다른 스레드의 통지 대기많으면 병목 의심
TIMED_WAITING시간 제한 대기sleep, timeout 대기
BLOCKED모니터 락 획득 대기많으면 락 경합 확인

멀티프로세스 vs 멀티스레드

구분멀티프로세스멀티스레드
예시Nginx worker, Chrome 탭Tomcat, Spring MVC
장점프로세스 격리 (안전)메모리 공유 (효율)
단점메모리 사용량 높음, IPC 비용동시성 문제 (동기화 필요)

Java 웹 서버(Tomcat)는 하나의 프로세스 안에서 멀티스레드로 요청을 처리한다.

자주 나는 실수

  • 스레드 풀 사이즈를 CPU 코어 수만 고려하고 I/O 대기를 무시한다.
  • 스레드 안전하지 않은 객체를 멀티스레드에서 공유한다 (SimpleDateFormat 등).
  • 스레드 풀을 사용하지 않고 매번 new Thread()로 생성한다.
  • 스레드 덤프에서 BLOCKED 스레드가 많은데 원인을 분석하지 않는다.
  • 스레드 로컬을 사용하고 스레드 풀 반환 시 정리하지 않는다.

핵심 요약

프로세스는 독립된 메모리 공간을 가지고, 스레드는 프로세스 내에서 힙을 공유하며 스택만 독립적입니다. Java 웹 서버는 멀티스레드 모델이며, 스레드 풀로 스레드를 재사용합니다.

스레드 풀 사이즈는 CPU 바운드/I/O 바운드 특성에 따라 결정합니다. 스레드 덤프로 BLOCKED, WAITING 상태의 스레드를 분석하면 병목 원인을 찾을 수 있습니다.

꼬리 질문

관련 문서