1️⃣ 테스트 목적
JDK 21부터 정식 지원된 Virtual Thread는 수십만 개의 경량 스레드를 처리할 수 있는 새로운 동시성 모델입니다.
그렇다면 실제로 일반 Thread와 비교했을 때 성능 차이는 얼마나 날까요?
단순하지만 직접 실험해봤습니다.
테스트 목적:
10,000개의 스레드를 각각 일반 Thread와 Virtual Thread로 생성하고, 전체 실행 시간을 비교합니다.
2️⃣ 테스트 시나리오
- 각각 10,000개의 Thread를 생성해서 간단한 출력 작업 수행
- 일반 Thread vs Virtual Thread의 전체 실행 시간 비교
- 환경: windows 10, Java 21
3️⃣ 전체 테스트 코드 (Java 21 이상)
import java.time.Duration;
import java.time.Instant;
public class ThreadComparisonTest {
public static void main(String[] args) throws InterruptedException {
int THREAD_COUNT = 10_000;
System.out.println("===== Java Thread 비교 테스트 시작 =====");
System.out.println("스레드 개수: " + THREAD_COUNT);
System.out.println("실행 환경: Windows 10, Java 21 이상\n");
// 일반 Thread 테스트
System.out.println("일반 Thread 테스트 시작...");
Instant startClassic = Instant.now();
Thread[] classicThreads = new Thread[THREAD_COUNT];
for (int i = 0; i < THREAD_COUNT; i++) {
classicThreads[i] = new Thread(() -> {
System.out.print(""); // 최소 동작
});
classicThreads[i].start();
}
for (Thread t : classicThreads) {
t.join();
}
Instant endClassic = Instant.now();
long classicTime = Duration.between(startClassic, endClassic).toMillis();
System.out.println("일반 Thread 소요 시간: " + classicTime + " ms\n");
// 🪄 Virtual Thread 테스트
System.out.println("🪄 Virtual Thread 테스트 시작...");
Instant startVirtual = Instant.now();
Thread[] virtualThreads = new Thread[THREAD_COUNT];
for (int i = 0; i < THREAD_COUNT; i++) {
virtualThreads[i] = Thread.ofVirtual().start(() -> {
System.out.print(""); // 최소 동작
});
}
for (Thread t : virtualThreads) {
t.join();
}
Instant endVirtual = Instant.now();
long virtualTime = Duration.between(startVirtual, endVirtual).toMillis();
System.out.println("🪄 Virtual Thread 소요 시간: " + virtualTime + " ms\n");
// 비교 결과 출력
System.out.println("=== 결과 요약 ===");
System.out.println("일반 Thread 평균 시간: " + classicTime + " ms");
System.out.println("🪄 Virtual Thread 평균 시간: " + virtualTime + " ms");
if (classicTime > virtualTime) {
System.out.println("Virtual Thread가 " + (classicTime - virtualTime) + " ms 더 빠릅니다!");
} else {
System.out.println("Thread 성능이 거의 비슷하거나, 테스트 환경에 따라 차이가 없습니다.");
}
}
}
4️⃣ 실행 결과 (평균값)
항목 | 실행시간 |
일반 Thread | 약 1600 ~ 2500ms |
Virtual Thread | 약 200 ~ 400ms |
⚠️ 스레드 개수가 많아질수록 일반 Thread는 성능이 급격히 저하됨
✅ Virtual Thread는 수만 개 수준에서도 부드럽게 동작
5️⃣ 실전에서 얻은 인사이트
- 일반 Thread는 시작부터 CPU 부하가 체감될 정도로 느려짐
- Virtual Thread는 JVM에서 직접 스케줄링되기 때문에 훨씬 가볍고 빠름
- 특히 I/O 위주의 작업에 유리하며, "비동기 코드를 동기처럼" 작성할 수 있어 가독성도 뛰어남
6️⃣ 결론 및 요약 ☑️
항목 | Platform Thread | Virtual Thread |
생성 비용 | 높음 (MB 단위 스택) | 낮음 (KB 단위) |
수십만 개 생성 | ❌ 어려움 | ✅ 가능 |
Blocking I/O | 리소스 낭비 큼 | 리소스 효율적 |
코드 구조 | 복잡 (Callback 등) | 단순 (동기처럼 작성) |
적합한 용도 | CPU 바운드 | I/O 바운드, 대규모 요청 처리 |
도입 버전 | Java 1.0 ~ | Java 21 (Stable) |
✅ Virtual Thread는 고부하 환경이나 대량 연결 처리와 같이 수많은 작업을 동시에 처리해야 하는 상황에서 플랫폼 스레드의 대안이자 미래형 동시성 모델이다.
🚀 배운 점
1️⃣ Virtual Thread는 성능이 좋을 뿐 아니라 코드 구조도 단순화할 수 있다
2️⃣ 기존 비동기 기반의 복잡한 코드에서 벗어나, 동기식으로도 고성능 처리가 가능하다
3️⃣ Spring Boot, WebClient, JDBC 등에서도 Virtual Thread의 적용이 현실화되고 있어, 실무 도입 가능성도 높다
4️⃣ Virtual Thread의 가치를 제대로 활용하려면, 기존 Thread 동작 방식과의 차이를 먼저 명확히 이해하는 것이 중요하다
📚 참고자료