이 글은 스프링캠프 2025에서 박성훈 정승주님의 발표를 바탕으로 정리하여 작성한 글 입니다. 해당 과정에서 제 실수로 잘못된 정보를 기재 하였을 수도 있는 점 양해 부탁 드립니다.
JDK 13 이전 vs 이후 소켓 구현 변화
JDK 13 이전 (레거시 구현)
- PlainSocketImpl: JDK 1.0부터의 레거시 Java와 C 코드 혼합
- 네이티브 함수 위주의 소켓 구현
- OS Socket 자원을 FileDescriptor에 위임
- synchronized 메서드 사용으로 Virtual Thread 비호환
JDK 13 이후 (새로운 구현)
- NioSocketImpl: PlainSocketImpl의 드롭인 대체
- NIO 구현과 같은 JDK 내부 인프라 공유
- java.util.concurrent 락 사용으로 Virtual Thread 호환
NioSocketImpl의 핵심 동작
소켓 모드 전환
소켓은 처음에 블로킹 모드로 설정되다가, 타임아웃이나 Virtual Thread에서 블로킹 작업이 시도되면 논블로킹 모드로 변경
Virtual Thread에서의 I/O 처리 흐름
- Virtual Thread에서 소켓 읽기 시도
- 논블로킹으로 먼저 시도 (
tryRead()) - 데이터가 없으면 (
IOStatus.UNAVAILABLE) Poller에게 감시 요청 - VirtualThreads.park() 호출로 Virtual Thread 일시정지
- I/O가 준비되면 Virtual Thread가 unpark되어 재개
핵심 클래스들 상세
Poller 클래스
- 중단된 Virtual Thread를 재개하는 역할
- NioSocketImpl이 Poller에게 감시 요청
- 내부적으로 Selector API 사용
Selector API
- 등록된 소켓의 상태를 감지할 수 있는 API
- Selector API의 추상 클래스 구조
- OS별 구현체가 다름:
- Linux: EPollSelectorImpl (epoll)
- macOS: KQueueSelectorImpl (kqueue)
- Windows: WindowsSelectorImpl (select)
NativeDispatcher
- 실제 네이티브 소켓 연산 담당
- SocketDispatcher: 소켓 관련 네이티브 호출
- 연산 재시도 필요시 Poller가 감지
전체 흐름도
Virtual Thread 소켓 읽기 요청
↓
NioSocketImpl.read()
↓
tryRead() 시도
↓
데이터 있음? ──── YES ──→ 데이터 반환
↓ NO
IOStatus.UNAVAILABLE
↓
Poller.pollRead() 호출
↓
Selector에 감시 등록
↓
VirtualThreads.park()
↓
[Virtual Thread 일시정지]
↓
소켓에 데이터 도착
↓
Selector 이벤트 감지
↓
Virtual Thread unpark()
↓
다시 tryRead() 시도
↓
데이터 반환핵심 달성 목표
실제로는 논블로킹 수준의 IO를 수행하는 블록킹 IO
- 소켓 자체: 논블로킹 모드로 설정
- 애플리케이션 레벨: 기존과 동일한 블로킹 API 제공
- Virtual Thread: park/unpark로 블로킹 시뮬레이션
- 결과: OS 스레드 자원 효율성과 사용 편의성 모두 확보
시기와 배경
이 모든 재구현은 Virtual Thread 정식 출시 전에 미리 완료되었습니다:
| JEP | 버전 | 시기 | 내용 |
|---|---|---|---|
| JEP 353 | Java 13 | 2019 | Socket/ServerSocket 재구현 |
| JEP 373 | Java 15 | 2020 | DatagramSocket/MulticastSocket 재구현 |
| Virtual Thread | JDK 19 | 2022 | 프리뷰 버전 |
| Virtual Thread | JDK 21 | 2023 | 정식 릴리즈 |
레거시 지원
기존 구현으로 되돌리기 가능:
-Djdk.net.usePlainSocketImpl=true
결론
이런 구조로 Virtual Thread는 기존 블로킹 IO 코드를 전혀 수정하지 않고도 높은 동시성을 달성할 수 있게 되었습니다
'프로그래밍 > 자바' 카테고리의 다른 글
| resilience4j feign circuit 설정 이슈 (0) | 2025.03.26 |
|---|---|
| Java, Call By Value? Call By Reference? (0) | 2024.08.10 |
| [기록] Spring mockMvc test securityRequirements type (0) | 2024.03.17 |
| Virtual Thread & Hikari & Semaphore (1) | 2024.02.21 |
| 얼마나 좋아~~ JDK21 & Spring boot 3.2 Virtual Thread (2) | 2024.02.12 |