Java
Java Virtual Thread vs 기존 ThreadPool 구조 비교
마시멜로를찾아서
2025. 6. 19. 10:34
728x90
반응형
Java Virtual Thread vs 기존 ThreadPool 구조를 비교하는 실용적인 예제입니다.
비동기 요청 처리(WebFlux, WebClient, Kafka 등)에서 구조적 차이와 성능/코드 복잡도 비교가 명확히 드러납니다.
⚔️ 목적: 동일한 HTTP 요청 100개를 병렬로 처리
각 요청은 500ms sleep API 호출 시뮬레이션
🔁 1. 기존 ThreadPool (ExecutorService) 방식
ExecutorService executor = Executors.newFixedThreadPool(10);
List<Callable<String>> tasks = IntStream.range(0, 100)
.mapToObj(i -> (Callable<String>) () -> {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder(URI.create("https://httpbin.org/delay/0.5")).build();
return client.send(request, HttpResponse.BodyHandlers.ofString()).body();
}).toList();
long start = System.currentTimeMillis();
List<Future<String>> futures = executor.invokeAll(tasks);
executor.shutdown();
long elapsed = System.currentTimeMillis() - start;
System.out.println("ThreadPool 총 소요시간: " + elapsed + "ms");
⚠️ 단점:
- FixedThreadPool 이상으로 쓰레드 수 증가 시 GC 부하, CPU context switching
- 100개 요청이면 100개 쓰레드 필요 (Blocking 구조)
🚀 2. VirtualThread (Java 21) 방식
ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();
List<Callable<String>> tasks = IntStream.range(0, 100)
.mapToObj(i -> (Callable<String>) () -> {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder(URI.create("https://httpbin.org/delay/0.5")).build();
return client.send(request, HttpResponse.BodyHandlers.ofString()).body();
}).toList();
long start = System.currentTimeMillis();
List<Future<String>> futures = executor.invokeAll(tasks);
executor.shutdown();
long elapsed = System.currentTimeMillis() - start;
System.out.println("VirtualThread 총 소요시간: " + elapsed + "ms");
✅ 장점:
- 수천~수만 개의 Virtual Thread 처리 가능
- 커널 쓰레드와 다르게 Blocking 발생 시 Thread가 반납됨
- 코드 복잡도 없이 동기 방식처럼 코딩 → 비동기 효과
📊 성능 비교 (100개 요청, delay 500ms 기준)
항목 | ThreadPool (10개) | VirtualThread |
실행 시간 | 약 5~6초 | 약 0.6초 |
사용 스레드 수 | 10 | 최대 5~6개 커널 쓰레드만 |
코드 가독성 | 중 | 매우 높음 |
확장성 | 제한적 (20~500개 쓰레드가 한계) | 수만 개 처리 가능 |
📦 실무 적용 포인트
대상 | 권장 방식 |
WebFlux + Reactor 기반 | 그대로 non-blocking 유지 |
내부 Blocking API + 동기 호출 | Virtual Thread 적극 활용 |
Kafka Consumer 처리 | Virtual Thread 가능 (Spring Kafka 3.1 이상) |
외부 HTTP 호출 | WebClient, 또는 VirtualThread + HttpClient |
🔧 스프링 설정 팁 (Spring Boot 3.2+)
@Bean
public TaskExecutor applicationTaskExecutor() {
return TaskExecutors.virtual();
}
728x90
반응형