Java 21 부터는 Virtual Thread 사용이 가능합니다. Java 21의 Virtual Thread에 대해 알아보겠습니다.
📌 Java의 Thread
Java에서 Thread는 OS Thread를 래핑하여 사용합니다. 따라서 Java에서 Thread를 사용하면, OS Thread를 사용한 것과 같습니다. OS Thread는 생성 갯수가 제한적이고, 생성하거나 유지하는 데에 비용이 비쌉니다. 이로 인해 애플리케이션에서는 Thread를 효율적으로 사용하기 위해 Thread Pool을 사용합니다.

기본적으로 Web Request는 Thread Per Request, 하나의 요청 당 하나의 스레드가 필요합니다. 처리량을 높이려면 스레드가 많이 필요한데, OS Thread를 무한정으로 늘릴 순 없습니다.
Thread에서 I/O 작업을 처리하면 Blocking이 발생합니다. 이러한 상황에서 작업을 처리하는 시간보다 대기하는 시간이 더 긴 경우도 존재합니다.

만약 Blocking이 발생했을 때 내부 스케쥴링을 통해 다른 작업을 처리한다면, 높은 처리량을 확보할 수 있습니다.
📌 Virtual Thread

이미지를 보면, Application은 Virtual Thread를 사용합니다.
Virtual Thread가 작업을 할당받게 되면 Carrier Thread와 연결됩니다. 그러다 Blocking이 발생하게 되면, Carrier Thread로부터 unmount되고, Carrier Thread는 놀게 됩니다. 그러면 Carrier Thread는 다른 Virtual Thread를 mount 시킵니다.
이전에는 Blocking이 발생했을 때에는 작업이 완료될 때까지 Blocking을 기다렸지만, mount/unmount를 수행함으로써 다른 작업을 할 수 있게 됩니다. OS Thread 제한에 비해 Virtual Thread는 더 많이 생성할 수 있습니다.
이로 인한 Platform Thread와 Virtual Thread가 사용 가능한 자원의 차이는 존재합니다.

Virtual Thread는 개수가 많아질 수 있기 때문에 사용 자원이 비교적 적게 유지됩니다.
📌 성능 비교
@GetMapping("/virtual")
public String getBlockingResponse() throws InterruptedException {
Thread.sleep(1000);
return "OK";
}
위 작업에 3000회의 요청이 있을 때 Platform Thread는 TPS가 약 200에 가깝게 유지되었습니다. 200으로 유지된 이유는 톰캣의 기본적인 Thread max값이 200이기 때문에 200 정도로 유지된 것으로 추측할 수 있습니다.
하지만 Virtual Thread의 경우 TPS가 약 3000 가까이 나왔습니다. 단순히 Thread.sleep만 하였지만, I/O와 관련된 부분이 있을 때 Virtual Thread를 사용한다면 큰 효과를 볼 수 있음을 알 수 있습니다.
@GetMapping("/query")
public String getQueryResult() throws InterruptedException {
return jdbcTemplate.queryForList("select sleep(1)'").toString();
}
위와 마찬가지로 3000회의 요청이 있을 때, Platform Thread는 TPS가 약 150으로 나왔습니다. 이는 데이터베이스의 지정된 max-connection이 151로 설정되어 있으므로 이 것이 원인임을 추측할 수 있습니다.
그러나 Virtual Thread는 에러가 발생했습니다. 에러의 내용은 connection timeout인데, 그 이유는 Virtual Thread는 3000의 Throughput을 모두 소화하고, 데이터베이스 커넥션을 기다리게 됩니다. 이 과정에서 타임아웃이 발생해서 예외가 발생한 것입니다.
Virtual Thread를 적용하면 Throughput이 높아져서 무조건 좋을 것 같지만, 이처럼 주의해야할 부분들이 존재합니다.
📌 유의사항
- I/O Blocking이 발생하는 경우, Virtual Thread는 효율적
- CPU Intensive한 작업에는 적합 X
- Virtual Thread는 기다림에 대한 개선
- Pinning 주의
- Virtual Thread 내에서 synchornized, 네이티브 메서드를 사용한 경우, Carrier Thread가 Blocking
- 제한된 리소스의 경우 semaphore 사용
참고
https://techblog.woowahan.com/15398/
https://www.youtube.com/watch?v=vQP6Rs-ywlQ
'자바' 카테고리의 다른 글
JVM과 가비지 컬렉션 (0) | 2025.01.11 |
---|---|
자바 상속에 대해서 알아보기 (0) | 2025.01.10 |