Java/JVM

[JVM 밑바닥까지 파헤치기] 12-3. 자바 메모리 모델과 스레드: 스레드

noahkim_ 2024. 12. 26. 01:06

저우즈밍 님의 "JVM 밑바닥까지 파헤치기" 책을 정리한 포스팅 입니다

 

1. 스레드 모델

  • 사용자 수준의 스레드와 운영체제의 커널 스레드를 어떻게 매핑하고 관리할 것인지에 대한 구조적 설계 방식

 

종류

항목 커널 스레드 사용자 스레드 하이브리드 스레드
구현 위치 커널 (운영체제 수준) 사용자 공간 (라이브러리 수준) 커널 + 사용자 공간
매핑 방식 커널 스레드 1개 ↔ 사용자 스레드 1개 커널 스레드 1개 사용자 스레드 N개 커널 스레드 N사용자 스레드 N개
시스템 콜 모든 스레드 작업에 필요 상황에 따라 사용
비용 높음 낮음 (컨텍스트 스위치 빠름) 중간
병렬 처리 ❌ (동시 실행 불가)
유연성 낮음 높음 (유저가 직접 관리) 높음
단점 커널 자원 한정, 생성 비용 큼 하나가 블로킹되면 전체 정지 구현 복잡도 높음
  • 핵심 메서드 모두가 네이티브 코드로 구현됨

 

2. 자바 스레드

  • 커널 스레드로 구현됨
  • ✅ 운영체제별 스레드 모델의 차이를 숨기는 통합 인터페이스를 제공
  • ➡️ 프로세서 할당: 스레드 간에 CPU 사용 권한은 운영체제의 스케줄러가 제어함
  • ➡️ 선점형 스케줄링: 스레드 우선순위를 통해 먼저 할당되도록 권고할 수 있음 (Thread.setPriority())

 

커널 스레드의 한계

  • ⚠️ 분산 시스템에서 동시 요청이 많을 때 병목이 됨
  • 생성, 전환, 블로킹 비용이 크고, 생성 수가 한정되어 있음

 

대안 (사용자 스레드 방식)

항목 코루틴
가상 스레드
정의 비동기 작업을 동기처럼 표현하는 경량 실행 단위
JVM이 관리하는 경량 스레드
실행 주체 사용자 공간
JVM 내부에서 사용자 모드 스케줄링
전환 방식 명시적 suspend/resume
JVM이 자동으로 중단/복원 (스택 프레임까지 관리)
스택 구조 스택리스 (상태를 클로저에 저장)
스택풀 (실제 스레드처럼 스택 프레임 전체를 JVM이 관리)
코드 스타일 비동기식 (suspend, await 필요)
기존 자바 동기식 코드와 동일 (Thread API 그대로 사용)
복잡도 높음 (호출 스택 복원, 상태 보존 등)
기존 스레드와 동일한 디버깅 패턴 적용 가능
전환 비용 낮음 (사용자 공간에서 전환)
낮음 (JVM 내부 전환)
블로킹 처리 직접 비동기 API를 사용해 non-blocking 처리
내부적으로 블로킹 시 다른 가상 스레드에게 양보
대표 예시 - Kotlin Coroutine
- Go Routine
- Python asyncio 
- Java 21 Thread.startVirtualThread()
- Java 21 Executors.newVirtualThreadPerTaskExecutor()