프로그래밍/Java

Virtual Thread (10분 테코톡)

개발정리 2024. 7. 13. 19:06

1. Thread 란


 

위 그림은 JVM 내부 Runtime Data Area이다. 

 

1) Heap

- new 명령어로 생성된 인스턴스가 저장되는 공간 

 

2) Method Area 

- 클래스, 변수, static, 정적 변수가 저장되는 공간 

- 안에 있는 runtime constant pool은 클래스 정보와 같은 메타 데이터가 저장되는 공간 

 

3) Thread

- 프로세스의 작은 작업 단위를 말한다. 

 

3-1) PC (Process Counter Register)

- 스레드 작업 흐름 단위를 저장하고 있다.

3-2) JVM Stack

- 메소드 스택을 저장.

- 메소드가 종료되면 메모리 공간에서 사라지게 된다.

3-2) Native Method Stack

- JNI (Java Nativce Interface) 이다. 

- 자바가 아닌 다른 언어로 이루어진 언어들이 스택으로 저장되는 공간 

 

 

2. Green Thread Model (N:1) 


 

1) User Level Thread

- 커널 상위에 존재한다. 

- User Library에서 구현된다.

- 구현되는 부분은 스레드 생성, 스케줄링 이관리되는 부분이 구현되어 있다.

 

2) Kernel Level Thread

- OS(kernel)에서 스케줄링하고 스레드 생성/제거를 담당한다. 

 

자바 초창기에는 ULT와 KLT가 N:1 로 이루어져있었다. 그리고 ULT를 원하는 만큼 만들 수 있었다. 이 때 하나의 ULT만 KLT에 연결을 할 수 있다. 만약 한 ULT가 Blocking이 되는 순간 모든 ULT가 전체 멈추가되는 상황이 발생하게 된다. 이것은 KLT는 프로세스 내부의 스레드가 어떻게 동작하는지 모르기 때문에 발생하는 문제이다. 

 

현재는 HW가 좋아지며 멀티코어가 표준이 되었는데, Green Thread Model과 같이 N:1로 될 경우 멀티코어의 효율을 살릴 수 없다.

 

 

3. 1:1 Thread Model


 

 

User Level Thread와 Kernel Level Thread가 1:1로 맵핑된다. 이 경우 하나가 Blocking 되어도 병렬도 수행이 가능하다는 장점을 가지게된다.  이 때, User Level Thread를 무한정 만들순 있지만 Kernel Level Thread 가 1:1로 맵핑되기 때문에 시스템 부하가 발생할 수 있다.

 

(OS들은 성능의 이점을 챙기기 위해 스레드 최대 개수를 제한하고 있다.)

 

 

4. Native Thread Model


 

위 모델은 우리가 기본적으로 알고 있는 자바 네이티브 스레드 모델이다. 

 

OS Thread와 JVM 안에서 관리되고 있는 Platform Thread가 있다. 아래 이미지와 같이 Platform Thread는 OS Thread를 랩핑하여 가지고 있다.

 

 

 

Solaris OS는 Platform Thread와 N:M의 관계를 가지고 있고, window와 Linux는 1:1의 관계를 가지고 있다. 

 

 

5. Virtual Thread Model


- JDK 19 Preview, JDK 21 Release

- 처리량이 높고, 유지 보수와 디버깅이 수월해지는 경량 스레드이다.

(디버깅이 수월하다는 것은 기존 스레드와 동작이 비슷하기 때문이다.)

 

 

Native Thread Model에서 Platform Thread와 같이 Carrier Thread는 OS Thread와 1:1로 맵핑된다. 이 때 Virtual Thread는 JVM 내부 스케줄링에 의해서 Virtual Thread가 스케줄링되고 Carrier Thread는 1:1로 맵핑된다.

 

 

Platform Thread는 사용 시 Blocking이 될 경우 대기 상태가 된다. Carrier Thread는 Virtual Thread와 연결되어 Blocking이 발생할 경우 대기상태가 되지 않는다. Virtual Thread를 잠시 중단시키고 다른 Virtual Thread를 가져와 작업을 수행한다.이는 CPU 효율을 최대로 발휘할 수 있다.

 

 

 

Carrier Thread에 Virtual Thread가 마운트 되면 Heap 메모리 영역에 Virtual Thread 정보를 저장하게 된다. 

 

1번 Virtual Thread에서 Blocking이 발생할 경우 Carrier Thread는 놀고있는 2번 Virtual Thread를 가져와 수행한다. 이 후 1번 Virtual Thread 작업이 끝나면 다시 Carrier Thread에 연결된다.

 

이렇게 다시 마운트 될 때 Heap 메모리 영역에 있던 method stack들을 모두 가져와서 다시 실행하게 된다. 

 

 

6. Virtual Thread 장점


1) 컨텍스트 스위칭 비용이 저렴하다.

- 기존 Native Thread Model은 Platform Thread로써 컨텍스트 스위칭이 Kernel 단에서 발생한다.

- OS 단에서 발생하는 컨텍스트 스위칭 비용이 JVM 내부에서 발생하는 컨텍스트 스위칭 비용보다 비싸다.

 

2) 기존보다 높은 처리량을 제공한다.

-  Thread가 쉬지 않고 최대 CPU를 사용하기 때문에 높은 처리량을 제공한다. 

 

3) CPU를 효과적으로 활용한다. 

 

 

7. Virtual Thread 주의할 점


 

1) 응답이 빠르지는 않다. 처리량이 더 높을 뿐이다.

 

2) ThreadLocal 사용을 신중히 해야한다.

- Virtual Thread는 정말 많이 생성할 수 있다. 그렇기 때문에 Thread마다 생성되는 ThreadLocal 사용을 신중히 해야한다.

 

3) Synchronized, Native method를 지양 → Avoid Pinning

- 이것들을 함께 사용하면 Carrier Thread가 대기 상태에 걸리게된다. 

- 이는 Platform Thread와 다를것이 없어지는 것이므로 사용 이점이 없게 된다. 

 

 

 

가상 스레가 스레드인가? 객체를 잘 만들어서 돌리는 것이 아닌가? 라는 의문에 Project loom 기술책임자는 아래와 같이 답 하였다.

 

 

"가상 스레드는 스레드다."

 

 

(참고)

https://www.youtube.com/watch?v=Q1jZtN8oMnU

 

'프로그래밍 > Java' 카테고리의 다른 글

thread - join()  (0) 2024.07.28
Virtual Thread (kakao tech)  (0) 2024.07.14
Java21 Virtual Thread  (0) 2024.07.06
Java Virtual Thread (13), 병목 현상(bottleneck)  (0) 2024.06.29
Java Virtual Thread (12), custom Executor, Scheduler  (0) 2024.06.29