Virtual Thread

KyeongHoon Lee·2024년 1월 5일

Java Virtual Thread

Virtual Thread?

  • JVM자체에서 스케줄링하여 사용할 수 있는 Java의 경량(Light Weight) 스레드입니다.
  • 동시성 고가용성 애플리케이션을 작성하고, 유지하고, 디버깅하는 데에 드는 노력을 줄이기위해 만든 경량 스레드입니다.
  • JDK 19 에서 처음 선보였으며, 2023년 9월에 JDK21 에서 정식으로 출시되었습니다.

Platform Thread

  • java에서 기존에 제공하던 방식의 Thread입니다.
  • OS Threadwrapping하여 제공하였으며, 이를 Platform Thread라고 칭합니다.
  • Platform ThreadOS Thread와 1:1로 대응되며, Platform Thread의 최대 개수는 OS Thread 개수에 의해 제한됩니다.
  • OS Thread와 대응되어 비용이 크기 때문에 보통 Thread Pool을 만들어 사용합니다.

Virtual Thread

Virtual Thread의 기본 구조

  • Platform Thread랑 똑같이 java.lang.Thread의 인스턴스입니다.
  • 하지만 특정 OS Thread와 묶이지 않습니다.
  • 기존에 Platform Thread처럼 OS Thread와 대응되는 Thread를 Carrier Thread라고 부릅니다.

용어 알기 : Mount, UnMount

  • Virtual Thread가 실행되다가 Blocking I/O 를 만난다면, Java Runtime은 다시 동작이 시작될 수 있을 때까지 Virtual Thread 수행을 연기시킵니다.
  • 이때, Virtual Thread와 Mount되어 연산을 수행하던 Carrier Thread는 기존 Virtual Thread와 Unmount되고, 다른 Virtual Thread와 Mount되어 작업을 수행합니다.

Scheduler

  • 기본 스케줄러로는 ForkJoinPool이 사용되고 있습니다.

Virtual Thread 실행해보기

  • 첫번째 방법 : Thread.ofVirtual().start()
  • 두번쨰 방법 : Thread.startVirtualThread()
public class VirtualThreadTest { 
	public static void main(String[] args) { 
    	Runnable runnable = () -> { String test = "test"; }; 
        Thread thread1 = Thread.ofVirtual().start(runnable); 
        Thread thread2 = Thread.startVirtualThread(() -> { String test = "test"; }); 
        if(thread1.isVirtual()){ 
        	System.out.println("thread1 is virtual thread"); 
        } 
        else { 
        	System.out.println("thread1 is not virtual thread"); 
        } 
        
        if(thread2.isVirtual()){ 
        	System.out.println("thread2 is virtual thread"); 
        } 
        else { 
        	System.out.println("thread2 is not virtual thread"); 
        } 
    } 
}
  • 위 코드를 실행하면 다음과 같이 출력됩니다.
thread1 is virtual thread 
thread2 is virtual thread

Spring Boot 에서의 Virtual Thread

  • Spring Boot에서는 설정파일 (application.yml, application.properties)파일에 다음과 같이 추가해주면 virtual thread를 사용합니다.
spring: 
  threads: 
      virtual: 
          enabled: true

Why??

  • Spring Boot의 경우 Request하나당 Thread하나가 할당됩니다.
  • 따라서 Blocking 이 일어나는 요청을 많이 수행해야 하는 경우 Virtual Thread가 빛을 발할 수 있습니다.

Pinned Virtual Thread

  • 다음 두가지 경우, virtual thread는 Carrier Thread에 고정됩니다.
    1. Virtual Thread가 안에서 synchronized block 혹은 method를 실행하는 경우
    2. Virtual Thread가 native method를 실행하거나, Foreign Function을 실행하는 경우

Virtual Thread 테스트해보기

항목내용비고
javaJDK 2121는 Virtual Thread가 정식 출시된 최초의 LTS 버전입니다.
spring bootSpring Boot 3.2Spring Boot 3.2부터 java 21을 지원합니다.
cpuApple M1 ProIntel Core i9-11900T와 벤치마크가 비슷했습니다.
memory16GB 
부하테스트ngrinder가상유저 296명이 1분간 요청

1초 Block 하는 API

@RestController
public class TestController {

    @GetMapping("/test")
    @ResponseBody
    public Map<String, String> test() throws InterruptedException {
        Map<String, String> result = new HashMap<>();
        Thread.sleep(1000);
        return result;
    }
}
  • 기존의 Platform Thread를 사용한 경우

  • Virtual Thread를 사용한 경우

바로 응답하는 API

@RestController
public class TestController {

    @GetMapping("/test")
    @ResponseBody
    public Map<String, String> test() {
        Map<String, String> result = new HashMap<>();
        return result;
    }
}
  • 기존의 Platform Thread를 사용한 경우

  • Virtual Thread를 사용한 경우

총 정리

  • TPS : Throughput Per Second - 초당 처리량
  • MMT : Mean Test Time - 평균 응답 시간
ThreadAPITPSMMTErr RateVusers
Platform Thread1초 Blocking199.71478.70.0%296
Virtual Thread1초 Blocking290.51024.75.8%296
Platform Thread바로 응답14307.312.327.3%296
Virtual Thread바로 응답13584.512.730.7%296
  • Blocking이 없는 경우 Platform Thread의 TPS가 더 잘나오고 있습니다.
  • Blocking을 하는 경우 Virtual Thread의 TPS가 더 잘나오고 있습니다.
  • Blocking하는 API가 많은 경우 Virtual Thread사용을 검토해볼만 할 것 같습니다.

참고

https://docs.oracle.com/en/java/javase/21/core/virtual-threads.html#GUID-DC4306FC-D6C1-4BCC-AECE-48C32C1A8DAA
https://openjdk.org/jeps/444#Thread-local-variables

profile
Back-end Engineer입니다.

0개의 댓글