스레드당 1MB는 옛말,
Virtual Thread가 가져온 성능 혁명
안녕하세요, code-resting입니다. 자바 개발자들을 오랫동안 괴롭혔던 문제 중 하나는 '스레드 비용'이었습니다. 요청 하나당 스레드 하나를 할당하는 방식은 동시 접속자가 늘어날수록 메모리와 컨텍스트 스위칭 비용을 감당하기 힘들었죠. 하지만 Java 21에서 정식 도입된 가상 스레드는 이 공식을 완전히 깨버렸습니다.
1. 플랫폼 스레드 vs 가상 스레드
기존의 자바 스레드(플랫폼 스레드)는 운영체제(OS)의 커널 스레드와 1:1로 매핑되었습니다. 이는 생성 비용이 비싸고 개수도 제한적이었죠.
- ❌ 기존 방식: 스레드 하나가 수백 KB~1MB의 메모리를 점유함. 수천 개만 생성해도 OOM 위험.
- ✅ 가상 스레드: JVM 수준에서 관리되는 경량 스레드. 스레드당 수십 바이트 수준으로, 수백만 개를 동시에 띄워도 문제가 없음.
2. 어떻게 이렇게 빠를까? (Mount/Unmount)
가상 스레드의 핵심은 논블로킹(Non-blocking)처럼 동작하면서 코드는 동기(Synchronous) 방식으로 짤 수 있다는 점입니다.
동작 메커니즘:
- 가상 스레드가 I/O 작업(DB 조회, API 호출 등)을 만나 대기 상태가 되면,
- 실제 실행을 담당하던 OS 스레드(Carrier Thread)에서 자신을 분리(Unmount)합니다.
- OS 스레드는 다른 가상 스레드를 즉시 처리하러 가고, I/O가 완료되면 다시 합체(Mount)되어 작업을 이어갑니다.
3. 실전 적용: 톰캣(Tomcat)을 가볍게!
Spring Boot 3.2 이상을 사용한다면 단 한 줄의 설정으로 내장 톰캣의 스레드 모델을 가상 스레드로 바꿀 수 있습니다.
# application.yml
spring:
threads:
virtual:
enabled: true
이제 더 이상 max-threads 개수를 고민하며 스레드 풀 튜닝에 시간을 쏟지 않아도 됩니다.
4. 주의사항: Pinning 현상
⚠️ 모든 곳이 정답은 아닙니다.
synchronized 블록 내부에서 가상 스레드를 사용하면 OS 스레드가 해제되지 못하고 고정되는 Pinning 현상이 발생할 수 있습니다. 이를 방지하려면 ReentrantLock으로 교체하는 등의 작업이 필요합니다.
💡 마무리하며
가상 스레드는 자바의 비동기 프로그래밍 난이도를 대폭 낮춰준 축복과 같은 기능입니다. 리액티브 프로그래밍(WebFlux)의 복잡함 없이도 높은 처리량(Throughput)을 얻을 수 있죠. 2026년 백엔드 아키텍처를 고민하신다면, 가장 먼저 Java 21 업그레이드를 검토해 보시기 바랍니다.
'JAVA' 카테고리의 다른 글
| 코드가 우아해진다! Java 21 Record와 패턴 매칭(Pattern Matching) 완벽 가이드 (0) | 2026.03.26 |
|---|---|
| 반복적인 getter/setter는 이제 그만! MapStruct로 우아하게 DTO 변환하기 (0) | 2026.03.10 |
| 서버 부팅이 0.1초? GraalVM Native Image로 Java의 한계를 넘어서기 (0) | 2026.03.01 |
| 자바 개발자의 코틀린 전환기: Spring Boot + Kotlin 조합이 2026년에도 필수가 된 이유 (0) | 2026.02.28 |
| The Java, 코드를 조작하는 다양한 방법 (0) | 2021.09.01 |
댓글