Virtual thread

기존 스레드 방식(Native thread)

blog/Backend/Java/attachments/v1.png
기존에는 JVM 스레드가 커널 스레드에 1:1 대응되는 방식으로 사용되었습니다.

특징

  1. 가상 스레드에 비해 컨텍스트 스위치 비용이 큼
  2. 생성을 위해선 커널과 통신하여 스케줄링해야 하므로, 시스템 콜을 이용하기 때문에 생성 비용도 작지 않음

Virtual thread의 방식

blog/Backend/Java/attachments/v2.png

특징

  1. 가상 스레드는 일반 스레드의 약 1%의 작은 메모리를 가지고 있기 때문에 컨텍스트 스위치 비용이 작음
  2. JVM을 통해 생성하므로 시스템 콜과 같은 커널 영역의 호출이 적음

동작과정

blog/Backend/Java/attachments/v3.png

  1. runContinuation(실행될 virtual thread의 작업)을 carrier thread의 workQueue에 push
  2. Work queue에 있는 runContinuation들은 forkJoinPool에 의해 work stealing 방식으로 carrier thread에 의해 처리
  3. 처리되던 runContinuation들은 I/O, Sleep으로 인한 interrupt나 작업 완료 시, work queue에서 pop되어 park과정에 의해 다시 힙 메모리로 되돌아감

*work stealing: 한 스레드의 작업 queue가 비게 되면 다른 thread의 작업 queue에서 task를 가져와서 작업

장단점

장점

  1. 네트워크 IO 같은 interrupt 기간이 긴 작업에서 높은 효율을 보임
  2. Reactive 방식과 같이 기존에 MVC로 작성된 코드를 대부분 수정할 필요가 없으며, Reactive의 러닝커브의 부담을 질 필요가 없음

단점 및 주의사항

  1. CPU bound 작업에는 Native thread보다 비효율적
  2. 매우 많은 thread가 생성되기 때문에, thread마다 생성되는 Thread local의 사용에 매우 주의해야함 → Scoped Value라는 보완 방안 존재
  3. Pinned issue: synchronized, parallelStream, 네이티브 메서드를 사용하면 virtual thread가 carrier thread에 고정되므로 사용자제 → virtual thread에서 synchronized는 Reentrant lock으로 대체하면 방지가능

사용법

spring boot 3.2 이상

spring:
	threads:
		virtual:
			enabled: true

Mysql connector/J 버전

implementation 'com.mysql:mysql-connector-j:9.+'

Mysql connector/J는 9.0.0 버전에서 synchronized를 Reentrant Lock으로 대체하여 virtual thread의 사용 효율을 늘렸다.

MySQL Connector/J 9.0.0 Release Notes

Reference.

[Project Loom] Virtual Thread에 봄(Spring)은 왔는가 | 카카오페이 기술 블로그
Java의 미래, Virtual Thread | 우아한형제들 기술블로그