Java 21+ 가상 스레드: 활용 사례, 스케줄링 경계와 전환 방법
기준: Java 21 LTS. Java 24/25의 가상 스레드 구현과 구조적 동시성 API는 대상 JDK에 따라 다시 확인해야 합니다.
1. 어떤 경우에 적합한가
가상 스레드는 네트워크, 파일 또는 데이터베이스 I/O에서 블로킹되는 작업이 많은 경우에 적합합니다. 블로킹되는 동안 가상 스레드는 언로드될 수 있으며, 플랫폼 스레드는 다른 작업을 계속 처리합니다.
가상 스레드로 CPU 집약적 작업에 더 많은 연산 능력을 제공할 수는 없으며, 데이터베이스 연결 풀, 원격 서비스 또는 스레드 안전 컬렉션의 용량을 늘려 주지도 않습니다.
2. 최소 사용법
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
Future<Response> future = executor.submit(() -> client.fetch(request));
Response response = future.get();
}
가상 스레드를 무제한으로 하류 호출 체인에 이어 붙이지 마세요. Semaphore, 연결 풀, 요청 예산을 사용해 동시성을 제한하세요.
3. 전환 시 확인할 사항
ThreadLocal에 큰 객체가 저장되는지, 블로킹 호출이 실제로 언로드될 수 있는지, synchronized 임계 영역이나 잠금 경쟁, JNI 또는 네이티브 블로킹이 있는지, 취소와 타임아웃이 전파되는지 확인합니다.
JDK 21 시절의 pinning 진단은 여전히 유용합니다. 대상 JDK로 업그레이드한 뒤에는 해당 JEP와 릴리스 노트를 다시 읽고, 특정 버전의 내부 구현을 API 약속으로 받아들이지 마세요.
4. 비동기 API와의 비교
가상 스레드는 스레드 오버헤드를 줄여 동기식 블로킹 코드를 실행할 수 있게 합니다. 반면 비동기 API는 명시적인 continuation이나 이벤트 루프를 사용해 블로킹을 피합니다. 선택할 때는 스레드 수만 보지 말고 팀의 모델, 라이브러리 호환성, 디버깅 방식, 하류 서비스의 처리 능력을 고려해야 합니다.
5. 부하 테스트 방법
플랫폼 스레드, 가상 스레드, 비동기 구현을 각각 테스트할 때에는 동일한 연결 풀, 타임아웃, 부하와 하류 서비스를 사용해 처리량, 지연 시간, 메모리, 취소, 장애 복구를 측정하세요. CPU 집약적 벤치마크 결과만으로 I/O 성능에 관한 결론을 내리지 마세요.