본문 바로가기

소프트웨어-이야기/프로그래밍 언어와 프레임워크

VirtualThread 아는 체하기

(1) Virtual Thread이란?

JDK 21에 추가된 경량 쓰레드이다. OS 쓰레드를 사용하지 않고 JVM 내부 스케줄링을 통해 쓰레드를 생성한다.
수십만~수백만개의 쓰레드를 동시에 사용할 수 있다.

(2) 일반 Thread이란?

기존의 일반 Thread는 OS Thread를 그대로 매핑한 것이다. 이를 Platform Thread라고 한다.
Java Thread는 실제로 OS Thread를 사용한 것이다. Thread를 생성할 때 커널 영역에 접근하기 위해, 시스템 콜을 해야한다. 이로 인하여 오버헤드가 발생한다.

이러한 배경으로 생성 갯수가 제한적이고, 생성하고 유지하는 비용이 크다.
그래서 Thread를 무한히 생성할 수 없기 때문에 Thread Pool으로 관리해왔다.
미리 Thread를 만들어두고, 재사용하고, 생성 개수를 제한해왔다.

\

(3) Virtual Thread의 등장 배경

(3-A) 기존 Thread 구조의 한계

기본적인 web request 처리 방식은 Thread per request이다. 하나의 요청 당, 하나의 쓰레드이다.
처리량을 높이려면 쓰레드를 늘려야하나, OS Thread의 제약으로 무한히 늘릴 수 없다.

(3-B) Blocking I/O 으로 인한 대기 시간 증가

Thread에서 I/O 작업을 처리할 때 Blocking이 일어난다. 즉, 작업을 처리하는 시간보다 대기하는 시간이 길다.

(3-C) Reactive Programming의 한계

Thread 대기 시간을 줄이기 위해 Webflux 같은 개념이 등장했다. 그러나 코드를 작성하고 이해하기 어렵다.
Reactive Programming 을 하려면 reactive를 지원하는 라이브러리를 사용해야한다. 그런데 레퍼런스가 부족해서 사용하기 쉽지 않다.

 

(4) Virtual Thread의 장점

  • 처리량이 높다. 
    • Blocking I/O 줄일 수 있다.
    • 쓰레드 사용 메모리가 적다.  
  • 러닝 커브가 낮다
    • 기존 스레드 구조를 그대로 활용
    • MVC 환경의 동기식 스타일로 쉽게 코딩을 할 수 있다.

 

(5) Virtual Thread 구조

(6) Virtual Thread 사용팁 

  • threadpool이 없다. 태스크가 필요하면 virtual thread를 쭉쭉 만들자. 
  • GC가 알아서 메모리를 정리해주길 기다리자.
  • synchronized block이나 JNI을 사용하는 경우 worker thread (platform thread/carieer thread)가 고정되어 pinning 현상이 발생할 수 있다. ReentrantLock을 사용하여 우회하자. 

(7) 기존 Thread이 여전히 필요한 상황

기존 Thread와 Virtual Thread는 각각 장단점이 있다.

Virtual Thread은 Blocking I/O가 발생하는 작업의 대기 시간을 줄여주는 이점이 있다. 그러나 CPU 작업량이 높은 경우에는 큰 이점이 없다.

Virtual Thread를 무한히 늘리더라도 물리 시스템이 이를 받아주지 못하는 경우가 있다. 예를 들어, DB Connection이 그러하다. 이 경우, 기존 Thread와 Thread Pool을 사용하여 적정 사용량을 조정해야한다.

(8) 참고자료