JDK21 이 나온지 거의 2년이 되가는 시점에 너무 늦은 글이기도 하나 최근에 프로젝트를 하나 새로 만들면서 도입하면서 글을 새로 작성해본다. Java 21이 정식 출시되면서 가장 주목받는 기능 중 하나는 Virtual Thread이다.
기존의 무거운 플랫폼 스레드와는 달리, 경량화된 경합 구조를 제공함으로써 병렬성 및 확장성에서 큰 이점을 준다.
이번 글에서는 Java 21의 Virtual Thread에 대한 이해와, 이를 실제 프로젝트에 어떻게 적용했는지 정리해보았다.
new Thread() 혹은 ExecutorService 기반의 스레드는 OS 레벨 자원을 직접 사용한다.
수천 개 이상의 동시 처리에 한계가 존재 (스레드 생성 비용, 컨텍스트 스위칭 비용 등)
블로킹 I/O를 처리할 때, 해당 스레드가 자원을 점유한 채 대기 → 낭비
java.lang.Thread.ofVirtual().start() 로 생성
경량화된 스레드: OS가 아닌 JVM 내부 스케줄러에서 관리
수천~수만 개의 스레드도 부담 없이 생성 가능
기존 API (예: Runnable, ExecutorService)와도 호환됨 → 러닝커브 낮음
"블로킹 코드를 유지하면서도 비동기적 성능을 확보할 수 있다."
CompletableFuture
, Reactor
같은 복잡한 비동기 방식 필요자세한 코드 보실분은 GitHub에 올려놨습니다.
-> https://github.com/LeeKangJun33/-Virtual-Threads.git
ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();
List<CompletableFuture<SearchResult>> futures = keywords.stream()
.map(keyword -> CompletableFuture.supplyAsync(() -> searchService.search(keyword), executor))
.toList();
List<SearchResult> results = futures.stream()
.map(CompletableFuture::join)
.toList();
Virtual Thread로 각 검색 요청을 병렬 처리
Spring Boot + JPA와도 무리 없이 호환됨
기존 리액티브 방식보다 간결해져서 유지보수 에도 좋아진거같다.
Virtual Thread 덕분에 복잡한 비동기 처리 없이도 성능 향상이 가능했습니다.
검색, 크롤링, 외부 API 요청 등 병렬성이 필요한 작업에 최적입니다.
아직 실서비스 적용 전에는 안정성 테스트가 필요하지만, 충분히 실전 투입 가능한 기술이라고 생각합니다. 아직 좀더 다듬어야 할 부분이 많지만 그래도 충분하다고 생각합니다.
Java는 안정적이지만 무겁고 느리다는 인식이 있었지만,
Java 21의 Virtual Thread는 그런 편견을 확실히 깨줄 수 있는 변화 라고 생각합니다.