1. Java Virtual Thread?
Java Virtual Thead ๋ LTS ์ธ Java21 ๋ถํฐ ์ ์ ๋์ ๋ ๊ฒฝ๋์ฑ ์ค๋ ๋์ด๋ค.
๊ธฐ์กด ์๋ฐ ์ค๋ ๋ ๋ชจ๋ธ์ OS scheduler ๋ฅผ ํตํด ์ค์ผ์ค๋งํ๋ ์ค๋ ๋ ๋ชจ๋ธ์ธ ๋ฐ๋ฉด,
๊ฐ์ ์ค๋ ๋๋ JVM ์์ ์ค์ผ์ค๋งํ๋ ๊ฒฝ๋์ฑ ์ค๋ ๋ ๋ชจ๋ธ์ด๋ค.
JVM ์์ฒด์ ์ธ ๋ด๋ถ ์ค์ผ์ค๋ง์ ํตํด ๊ธฐ์กด ์ค๋ ๋์ ๋นํด ์ต๋ ๊ฐ์ฉ ์ค๋ ๋ ์๋ฅผ ์ฆ๊ฐ์์ผ
๋์ ์ฒ๋ฆฌ๋์ ๋ฌ์ฑํ๊ธฐ ์ํ ๋ชฉ์ ์ผ๋ก ๋์
๋ ๊ฐ๋
์ด๋ค.
2. Java Thread ์ JNI ๊ธฐ๋ฐ์ผ๋ก ์ค๋ ๋๋ฅผ ์์ฑํ๋ค.
๊ธฐ์กด ์ค๋ ๋๋ OS Thread ๋ฅผ ๋ํํ ํํ๋ก OS ์ค๋ ๋์ ์ ์ ์ค๋ ๋๋ฅผ 1:1 ๋งคํํ๋ ํํ์ด๋ค.
๊ธฐ์กด ์ค๋ ๋์ ์คํ๊ณผ ์์ฑ์ JNI(Java Native Interface) ๊ฐ ๋ด๋นํ๋ค. JNI ๋ ๋ค๋ฅธ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด(์ฃผ๋ก C, C++) ๋ก ์์ฑ๋ ๋ค์ดํฐ๋ธ ์ฝ๋ ๊ฐ์ ์ํธ ์ด์ฉ์ ๊ฐ๋ฅํ๊ฒ ํ๋ ํ๋ ์์ํฌ์ด๋ค. ์ฆ, JVM ์์ ๋ค๋ฅธ ํ๋ก๊ทธ๋๋ฐ ์ธ์ด๋ฅผ ์ฌ์ฉํ ์ ์๋๋ก ์ง์ํจ์ ์๋ฏธํ๋ค.
Thread ํด๋์ค์ ๋ด๋ถ ์ฝ๋๋ฅผ ํ์ธํ๋ฉด native ํค์๋๋ฅผ ํ์ธํ ์ ์๋ค. JNI ๊ฐ ํด๋น ๋ถ๋ถ์ ๋ด๋นํ์ฌ JVM ๋ด์ ์คํ๊ณผ ๋ถ๋ฆฌ๋์ด ์๋ ๋ค์ดํฐ๋ธ ๋ฉ์๋ ์คํ(Native Method Stack) ์ ์ฌ์ฉํด C ์ธ์ด๋ฅผ ์คํ์ํจ๋ค.
public class Thread implements Runnable {
private native void start0();
public synchronized void start() {
// ...
try {
start0();
started = true;
} finally {
//...
}
}
}

[์ค๋ ๋ start() ๋ฉ์๋ ํธ์ถ ์ ๋ฆฌ]

3. ๊ธฐ์กด ์ค๋ ๋์ ๋ฌธ์ ์ : Blocking ์ผ๋ก ์ธํ ๋ฆฌ์์ค ๋ญ๋น ๋ฐ ์ฒ๋ฆฌ๋ ํ๊ณ
๊ธฐ์กด ์ค๋ ๋๋ OS level thread ๋ฅผ ์์ฑํด ๋ํํ ํํ์ด๋ค. ์ด๋ฅผ ํ๋ซํผ ์ค๋ ๋(platform thread) ๋ก ์ ์ํ๋ค.
๊ฒฐ๊ตญ ์ค์ ์ค๋ ๋๋ฅผ ์ฌ์ฉํ๋ ์ฝ๋๋ OS level thread ๋ฅผ ์ด์ฉํ๋ค. ํ์ง๋ง OS kernel ์์ ์ฌ์ฉํ ์ ์๋ ์ค๋ ๋ ๊ฐฏ์๋ ์ ํ์ ์ด๋ฏ๋ก ์ค๋ ๋๋ฅผ ๋ฌดํ์ ์ผ๋ก ๋๋ฆด ์ ์๋ ๋จ์ ์ด ์๋ค.
Spring Web ๊ณผ ๊ฐ์ด Thread per Request ๋ชจ๋ธ์์ I/O ์์
์ ์ฒ๋ฆฌํ๋ฉด ํด๋น ์์ฒญ์ด ์๋ฃ๋ ๋๊น์ง ํด๋น ์ค๋ ๋๋ Blocking ๋๋ค. ์ด๋ก ์ธํด ํด๋น ์ค๋ ๋๋ I/O ์์
์ด ์๋ฃ๋ ๋๊น์ง ๋๊ธฐํด์ผ ํ๋ฏ๋ก ๋ฆฌ์์ค ๋ญ๋น๊ฐ ๋ฐ์ํ ์ ์๋ค. ์ด๋ฅผ ๊ฐ์ ํ๊ธฐ ์ํด์ Blocking ๋ฐฉ์์ผ๋ก ์ธํด ๋๊ธฐํ๋ ๋ฆฌ์์ค ๋ญ๋น๋ฅผ ์ต์ํ์ ๊ดํ ๊ณ ๋ฏผ์ด ํ์ํ๋ค.
๋ํ ์ด์ ๊ฐ์ ๊ตฌ์กฐ๋ ๋์ ์ฒ๋ฆฌ๋์ ์์ด ํ๊ณ๊ฐ ์๋ค. ์ค์ผ์ผ ์์(scale-out) ์ ํตํด ์ ์ฒด ์ฒ๋ฆฌ๋์ ๋๋ฆด ์ ์์ง๋ง, ๋จ์ผ ์ ํ๋ฆฌ์ผ์ด์
์๋ฒ์ ์ฒ๋ฆฌ๋์ ๊ฐ์ ํ๊ธฐ ์ํด์๋ ์์ ์ด์ผ๊ธฐํ Blocking ๋ฐฉ์์ผ๋ก ์ธํ ์๊ฐ์ ์ต์ํํ๋ ๋ฐฉ๋ฒ์ ๊ดํ ๊ณ ๋ฏผ์ด ํ์ํ๋ค.
์ด์ ๊ฐ์ ๊ณ ๋ฏผ์ ํด๊ฒฐํ๊ธฐ ์ํด Non-blocking ๊ธฐ๋ฐ์ Reactive Programming ๋์ ์ ๊ฒํ ๊ฐ ํ์ํ๋ค. ํ์ง๋ง reactive programming ์ ์ฉ์ ์ํ ๋ฌ๋ ์ปค๋ธ๊ฐ ์กด์ฌํ๊ณ , ์๋ฐ๋ ์ค๋ ๋ ๊ธฐ๋ฐ์ผ๋ก ์ค๊ณ๋์ด ์ปจํ ์คํธ ํ์ธ์ ์ด๋ ค์์ด ์กด์ฌํ๋ค. (e.g. Exception)

4. ํด๊ฒฐํ๊ณ ์ ํ๋ ๋ฌธ์ : Virtual Thread ๋ฅผ ํตํ Blocking ๋ฐฉ์์ ๋ฆฌ์์ค ๋ญ๋น ๊ฐ์
์์ ๊ฐ์ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ์๋ฐ ์ง์์์๋ 2018๋ Project Loom ํ๋ก์ ํธ๋ฅผ ์ถ๋ฒํ๋ค. Project Loom ์ ์๋ฐ ๋์์ฑ ๋ชจ๋ธ์ ํ๊ธฐ์ ์ผ๋ก ๊ฐ์ ํ๊ธฐ ์ํ ํ๋ก์ ํธ์ด๋ค. ๊ฐ์ ์ค๋ ๋๋ฅผ ๋์ ํด ๊ธฐ์กด์ ๋ฌด๊ฑฐ์ด OS thread ๊ธฐ๋ฐ์ ๊ตฌ์กฐ๋ฅผ ๊ฐ์ ํ๊ณ ์ ํ๋ ๋ชฉ์ ์ด๋ค.
Project Loom ์ JVM ์ ํตํ ์ค์ผ์ค๋ง, KB ๋จ์ ์คํ(๊ธฐ์กด ์ค๋ ๋ : MB ๋จ์), ๊ธฐ์กด ์ฝ๋ ๋ณ๊ฒฝ ์ต์ํ๋ฅผ ํตํด ๊ธฐ์กด์ Blocking ๋ฐฉ์์ ๊ดํ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์๋ ๋ฐฉ๋ฒ์ ์ ์ํ๋ค.
๊ธฐ์กด์ ๋ฐฉ์๊ณผ์ ๊ฐ์ฅ ํฐ ์ฐจ์ด์ ์ ์์
์ค๋ ๋์ OS ์ค๋ ๋์ ๋ถ๋ฆฌ์ด๋ค. ์์
์ ๊ดํ ์ญํ ์ ๊ฐ์ ์ค๋ ๋์ ์์ํ๊ณ , OS ์ค๋ ๋์ ๋งคํํ๋ ์ฑ
์์ ์บ๋ฆฌ์ด ์ค๋ ๋(carrier thread)์ ์์ํ๋ค.
์ด๋ฅผ ํตํด ๋๋ฆด ์ ์๋ ์ฅ์ ์ ๊ฐ์ ์ค๋ ๋๋ ๋ธ๋กํน๋์ง๋ง, OS ์ค๋ ๋๋ ๋ธ๋กํน๋์ง ์๋๋ค๋ ์ ์ด๋ค. Non-blocking ๊ณผ ๊ฐ์ด OS ์ค๋ ๋๋ฅผ ๋๊ธฐ์ํค์ง ์์ ์ค๋ ๋ ์์์ ์ ์ฝํ์ฌ ์ฒ๋ฆฌ๋ ๊ฐ์ ์ ๊ธฐ๋ํ ์ ์๊ฒ ๋์๋ค.
(1) Virtual Thead ์ ๋์ ๋ฐฉ์
๊ฐ์ ์ค๋ ๋๋ JVM ์ค์ผ์ค๋ง์ ํตํด ๊ด๋ฆฌํ๋ ์ ์ ๋ ๋ฒจ ์ค๋ ๋์ด๋ค. ๊ฐ์ ์ค๋ ๋๋ ํ์ํ ๋๋ง OS ์ค๋ ๋๋ฅผ ์ฌ์ฉํ๋ค. ๋ง์ฝ I/O ์์ ์ผ๋ก ์ธํด ์์ ์ด ๋ธ๋กํน๋๋ฉด ์คํ์ ์ ์ฅํ๊ณ ์คํ ์ค์ธ OS ์ค๋ ๋๋ฅผ ๋ฐ๋ฉํ๋ค.
JVM ์ ๊ฐ์ ์ค๋ ๋์ OS ์ค๋ ๋๋ฅผ ์ฐ๊ฒฐํ๋ ์ค์ผ์ค๋ง์ ๋ด๋นํ๋ฉฐ, ์ด ์์ ์ mount/unmount ๋ผ ํ๋ค. (์ค์ ๋ด๋ถ ์ฝ๋์์๋ park/unpark ์ด๋ฆ์ผ๋ก ์ฌ์ฉํ๋ค.)
๊ฐ์ ์ค๋ ๋๋ ์บ๋ฆฌ์ด ์ค๋ ๋์ ์ฐ๊ฒฐ์ ํตํด OS ์ค๋ ๋์ ๋งคํํ๋ค. ๋ง์ฝ I/O ์์
์ผ๋ก ์ธํด ๋ธ๋กํน ๋๋ ๊ฒฝ์ฐ, JVM ์ค์ผ์ค๋ง์ ํตํด ์บ๋ฆฌ์ด ์ค๋ ๋์ ์ฐ๊ฒฐ์ ํด์งํ๊ณ (unmount), ๋ค๋ฅธ ๊ฐ์ ์ค๋ ๋์ ์ฐ๊ฒฐํ์ฌ ํด๋น ๊ฐ์ ์ค๋ ๋์ ์์
์ ์งํํ๋ค.(mount)

(2) Virtual Thread ์ ์ฅ์
i. ์ปจํ ์คํธ ์ค์์นญ ๋น์ฉ ์ ๊ฐ
๊ฐ์ ์ค๋ ๋๋ ์ปจํ ์คํธ ์ค์์นญ(context switching) ๋น์ฉ์ ์ ๊ฐํ ์ ์๋ค.
๊ธฐ์กด ํ๋ซํผ ์ค๋ ๋๋ OS ๋ ๋ฒจ์ ์ปจํ ์คํธ ์ค์์นญ์ด ๋ฐ์ํ๋ค. OS ๋ ๋ฒจ์ ์ปจํ ์คํธ ์ค์์นญ์ ์ปค๋์ ๊ด์ฌ๋ก ์ธํด ์์คํ ์ฝ, CPU ๋ ์ง์คํฐ ์ํ ์ ์ฅ, ์คํ ํฌ์ธํฐ ์ด๋๊ณผ ๊ฐ์ ์์ ์ผ๋ก ๋น์ฉ์ด ํฌ๋ค.
๋ฐ๋ฉด, ๊ฐ์ ์ค๋ ๋์ ์ ์ ๋ ๋ฒจ์ธ JVM ๋ด๋ถ์์ ์ฒ๋ฆฌํ๋ค. ์ฆ, ์ปจํ ์คํธ ์ค์์นญ์ ์ปค๋์ด ๊ฐ์ ์ด ์๋์ ์ผ๋ก ์ ๋ค.
๋ง์ฝ ์ค๋ ๋๊ฐ ๋ธ๋กํน ํธ์ถ์ ์ง์ ํ๋ฉด ํ์ฌ ์คํ ํ๋ ์์ heap์์ ๊ด๋ฆฌํ๊ณ , ์บ๋ฆฌ์ด ์ค๋ ๋๋ ์ฆ์ ๋ค๋ฅธ ๊ฐ์ ์ค๋ ๋๋ก ์ ํ๋์ด ๋น์ฉ์ด ๋ฎ๋ค. ์ด๋ก ์ธํด ๊ธฐ์กด ํ๋ซํผ ์ค๋ ๋์ ๋นํด ๋น ๋ฅธ ์ปจํ ์คํธ ์ค์์นญ์ผ๋ก ์ธํด ์ค๋ ๋ ๊ด๋ฆฌ์ ๊ดํ ๋ถ๋ด์ด ์ ๋ค.


ii. ์ค๋ ๋ ์์ฑ ๋น์ฉ ๊ฐ์
๊ธฐ์กด ํ๋ซํผ ์ค๋ ๋๋ JVM ๋ฉ๋ชจ๋ฆฌ ์์ญ ๋ด์์ ๊ฐ ์ค๋ ๋๋ณ๋ก ํ์ํ ๋ฉ๋ชจ๋ฆฌ ๊ณต๊ฐ์ ์๋ก ํ ๋นํ๋ค. (์. ํ๋ก๊ทธ๋จ ์นด์ดํฐ, ์คํ, ๋ค์ดํฐ๋ธ ๋ฉ์๋ ์คํ ๋ฑ)
๋ฐ๋ฉด, ๊ฐ์ ์ค๋ ๋๋ ์ด์๋ ๋ค๋ฅธ ๋ฐฉ์์ผ๋ก ๋์ํ๋ค. ๊ฐ์ ์ค๋ ๋๋ ์คํ ์ค์ธ ๊ฐ์ ์ค๋ ๋ ์ ๋ณด๋ ์บ๋ฆฌ์ด ์ค๋ ๋์ ๋ฉ๋ชจ๋ฆฌ ์์ญ์ ๊ณต์ ํ๊ณ , ๋ธ๋กํน๋ ์ํ์์๋ ์ค๋ ๋ ์ํ ์ ๋ณด๊ฐ ํ ์์ญ์ ์ ์ฅ๋๋ค.
์ฆ, ํ๋ซํผ ์ค๋ ๋๋ ์ค๋ ๋๋ง๋ค ๊ณ ์ ํ ๋ฉ๋ชจ๋ฆฌ ๊ณต๊ฐ์ ์๊ตฌํ๋ ๋ฐ๋ฉด, ๊ฐ์ ์ค๋ ๋๋ ์์์ ์บ๋ฆฌ์ด ์ค๋ ๋ ๋ฉ๋ชจ๋ฆฌ์ ํ์ ํ์ฉํจ์ผ๋ก์จ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋์ ์ค์ด๊ณ , ์ค๋ ๋ ์์ฑ์ ํ์ํ ์์ ์๋ชจ๋ฅผ ์ต์ํํ ์ ์๋ค.

5. ๊ฐ์ ์ค๋ ๋ ์ฌ์ฉ ์ ์ ์์ฌํญ : pinning
๊ฐ์ ์ค๋ ๋๋ ์๋ฐ ๋ฐํ์์ด ์ค์ผ์ค๋งํ๋ค.
์๋ฐ ๋ฐํ์์ ๊ฐ์ ์ค๋ ๋๋ฅผ ์คํํ ๋, ์ด๋ฅผ ์บ๋ฆฌ์ด ์ค๋ ๋์ ๋ง์ดํธ ์ํค๊ณ , ์ด ์บ๋ฆฌ์ด ์ค๋ ๋๋ ์ด์ ์ฒด์ ์ ์ํด ์ผ๋ฐ ์ค๋ ๋์ฒ๋ผ ์คํ๋๋ค. ๊ฐ์ ์ค๋ ๋๋ ์ฝ๋ ์คํ ๋์ค I/O์ ๊ฐ์ ๋ธ๋กํน ์์ ์ ๋ง๋๋ฉด ์บ๋ฆฌ์ด ์ค๋ ๋์์ ์ธ๋ง์ดํธ๋์ด ๋ค๋ฅธ ๊ฐ์ ์ค๋ ๋๊ฐ ํด๋น ์บ๋ฆฌ์ด ์ค๋ ๋๋ฅผ ์ฌ์ฉํ ์ ์๊ฒ ๋๋ค.
ํ์ง๋ง ๋ค์๊ณผ ๊ฐ์ ๊ฒฝ์ฐ์๋ ๊ฐ์ ์ค๋ ๋๊ฐ ์บ๋ฆฌ์ด ์ค๋ ๋์ ๊ณ ์ (pinned)๋์ด ์ธ๋ง์ดํธ๋์ง ๋ชปํ๋ค.
- synchronized ๋ธ๋ก์ด๋ ๋ฉ์๋ ์์์ ์คํ ์ค์ผ ๋
- ๋ค์ดํฐ๋ธ ๋ฉ์๋๋ ์ธ๋ถ ํจ์(์: Foreign Function and Memory API)๋ฅผ ์คํํ ๋
์ด์ ๊ฐ์ ํ์์ด ๋ฐ์ํ๋ฉด ์บ๋ฆฌ์ด ์ค๋ ๋๋ ์์
์ ์งํํ์ง ์๊ณ ํด๋น CPU ๋ ๊ฒฉ๋ฆฌ๋๋ค. ์ด๋ ์์คํ
์ฑ๋ฅ์ด ์ ํ๋๊ฑฐ๋ ๋ฐ๋๋ฝ๊ณผ ๊ฐ์ ๋ฌธ์ ๋ฅผ ์ผ๊ธฐํ ์ ์๊ธฐ ๋๋ฌธ์ ๊ฐ์ ์ค๋ ๋๋ฅผ ์ฌ์ฉํ๊ธฐ ์ด์ ์ ๊ณ ์ ์ด์ ๋ฐ์ ๊ฐ๋ฅ ์ง์ ์ ๋ฏธ๋ฆฌ ํ์ธํด์ผ ํ๋ค.
๊ฐ์ ์ค๋ ๋๋ฅผ ๊ฒํ ํ๊ณ ์๋ค๋ฉด ๊ฐ์ฅ ๋จผ์ ๊ฒํ ํด๋ณด์ผํ ์์๊ฐ synchronized ์ด๋ค.
synchronized ํค์๋๋ฅผ ์ฌ์ฉํ๋ค๋ฉด ๊ฐ์ ์ค๋ ๋๋ฅผ ์ธ๋ง์ดํธํ์ง ๋ชปํด pinned ์ํ๊ฐ ๋๋ค. ๊ทธ๋ฌ๋ฏ๋ก ๊ฐ์ ์ค๋ ๋๋ฅผ ๊ฒํ ํ๊ณ ์๋ค๋ฉด synchronized ์ฌ์ฉ์ ์ง์ํด์ผ ํ๋ค.
๋ง์ฝ ๋์์ฑ ํด๊ฒฐ์ ์ํด synchronized ๋ฅผ ์ฌ์ฉํ๊ณ ์๋ค๋ฉด ReentrantLock ์ผ๋ก ๋์ฒดํ๋ ๋ฐฉ์์ ๊ฒํ ํด์ผ ํ๋ค. ๊ทธ๋ฆฌ๊ณ synchronized ์ฌ์ฉ ์ง์ ์ ๊ฒํ ํด์ผ ํ๋ค๋ฉด ์ ํ๋ฆฌ์ผ์ด์ ๋ฟ๋ง ์๋๋ผ ์ฌ์ฉ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊น์ง synchronized ์ฌ์ฉ ์ฌ๋ถ๋ฅผ ๊ฒํ ํด์ผ ๊ณ ์ ์ด์ ๋ฐ์์ ๋ฐฉ์งํ ์ ์๋ค.

(1) Pinning ์ด์๋ฅผ ๊ฐ์ ํ Java24
[2025.04.15 update]
Java24 ๊ฐ 2025.03.18 ์ ๋์
๋ ๊ฐ์ ์ ์ค JEP 491: Synchronize Virtual Threads without Pinning ์ ์ดํด๋ณด๋ฉด ๊ธฐ์กด์ Pinning ์ด์๊ฐ ๊ฐ์ ๋์๋ค.
๊ธฐ์กด synchronized ๋ฉ์๋/๋ธ๋ก ๊ฐ์ ์ค๋ ๋๊ฐ ์ง์
ํ๋ฉด JVM ์ด ํด๋น ๊ฐ์ ์ค๋ ๋์ ์บ๋ฆฌ์ด ์ค๋ ๋๊ฐ ๋ชจ๋ํฐ๋ฅผ ๊ฐ์ง ๊ฒ์ผ๋ก ๊ธฐ๋ก ๋์๋ค. ํด๋น ์ด์๋ ์บ๋ฆฌ์ด๊ฐ ์ค๋ ๋๊ฐ ๋ค๋ฅธ ๊ฐ์ ์ค๋ ๋๋ก ๋ง์ดํธ ๋ ๋, ๊ธฐ์กด ๋ชจ๋ํฐ๋ฅผ ๊ฐ์ง ๊ฒ์ผ๋ก ์ค์ธํด ๋๊ธฐํ ์ด์๊ฐ ๋ฐ์ํ ์ ์์ด ์ด๋ฅผ ๋ฐฉ์งํ๊ธฐ ์ํด JVM ์ synchronized ๋ฉ์๋/๋ธ๋ก ๋ด์ ๊ฐ์ ์ค๋ ๋๊ฐ ์ธ๋ง์ดํธํ๋ ๊ฒ์ ๊ธ์งํ๊ณ , ์บ๋ฆฌ์ด ์ค๋ ๋๋ฅผ ๊ณ ์ ์์ผฐ๋ค. ํ์ง๋ง ์ด ๋ฐฉ์์ ๊ฐ์ ์ค๋ ๋์ ์ฅ์ ์ ์์ ๊ณ , ์คํ๋ ค ์ค๊ณ ์ ์ธ๋ถ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ synchronzied ๊น์ง ๊ณ ๋ คํด์ผ ํด์ ์ค๊ณ์ ์ผ๋ก ๊ณ ๋ คํด์ผ ํ๋ ์ฌํญ์ด ๋ง์์ง๋ ๋จ์ ์ด ์์๋ค.

Java24 ๋ถํฐ synchronized ๋ฉ์๋/๋ธ๋ก ๋ด์์ ๋ธ๋กํน๋๋ ๊ฐ์ ์ค๋ ๋๊ฐ ํ๋ซํผ ์ค๋ ๋๋ฅผ ํด์ ํ ์ ์๋๋ก JVM ์ ๊ฐ์ ํ๋ค. ์ด๋ฅผ ํตํด ๊ฐ์ ์ค๋ ๋๊ฐ ์บ๋ฆฌ์ด ์ค๋ ๋์ ๊ณ ์ (pinned) ๋๋ ์ํฉ์ ์ ๊ฑฐํ๊ณ ๋๊ธฐํ๋ฅผ ๊ณ ๋ คํด์ผ ํ๋ ์ํฉ์์ ๊ฐ์ ์ค๋ ๋์ ๋์ ์คํ์ด ๊ฐ๋ฅํด ์ ํ๋ฆฌ์ผ์ด์
ํ์ฅ์ฑ์ด ํฅ์๋์๋ค. ๋ํ, ๊ธฐ์กด Java ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์์ ์์ด, ๊ฐ์ ์ค๋ ๋์ syncrhonized ์ ํธํ์ฑ์ด ํ๋ณด๋์ด ๊ธฐ์กด์ ์ธ๋ถ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๊ดํ ๊ณ ๋ฏผ์ด ํ์ ํ ์ค์ด๋ค์๋ค.

ํ์ง๋ง ์ค์ ์ด์ ํ๊ฒฝ์์ Java24 ์ ๊ฐ์ ์ฌํญ์ ๋์
ํ๋ ๊ฒ์ ๊ณ ๋ฏผ์ด ํ์ํ๋ค. ์ผ๋ฐ์ ์ผ๋ก ์ด์ ์์ ์ฑ์ ์ํด์ ์ฃผ๋ก LTS (Long Term Support) Version ์ ์ฌ์ฉํ๋ค. ์์ฝ๊ฒ๋ Java24 ๋ LTS ๊ฐ ์๋๋ฏ๋ก ํด๋น ๋ฒ์ ์ ๋์
ํ๋ ๊ฒ์ ์๊ธฐ์์กฐ์ด๋ค. oracle read map ์ ํ์ธํด๋ณด๋ฉด 2025.09 ์ LTS ์ธ Java 25๊ฐ ์ถ์ ์์ ์ด๋ฏ๋ก ํด๋น ๊ฐ์ ์ฌํญ ์ ์ฉ์ ์ํด์๋ Java25 ๋์
์ ๊ณ ๋ฏผํด๋ณด๋ฉด ์ข์ ๋ฏํ๋ค.

6. ๊ฐ์ ์ค๋ ๋ ์ฌ์ฉ ๋ฐฉ๋ฒ
(1) ์๋ฐ์์ ์ฌ์ฉ ๋ฐฉ๋ฒ
๊ฐ์ ์ค๋ ๋๋ Java 21 ๋ถํฐ ์ ์์ผ๋ก ๋ฆด๋ฆฌ์ฆ ๋์ด Java21 ์ดํ ๋ฒ์ ๋ถํฐ ๊ฐ์ ์ค๋ ๋ ์ฌ์ฉ์ด ๊ฐ๋ฅํ๋ค.
์ค๋ ๋ ์์ฑ ๋ฐฉ๋ฒ์ Thread ํด๋์ค์ ๋น๋๋ฅผ ์ฌ์ฉํ๊ฑฐ๋ Exetutors ์์ ์ ๊ณตํ๋ ๋ฉ์๋๋ฅผ ์ฌ์ฉํ ์ ์๋ค.
Thread ํด๋์ค๋ ofVirtual() ๋ฉ์๋๋ฅผ ํตํด ๊ฐ์ ์ค๋ ๋๋ฅผ ์์ฑํ ๋น๋ ํด๋์ค๋ฅผ ์ ์ธํ ์ ์๋ค. ํด๋น ๋ฉ์๋ ์ ์ธ ์ดํ start() ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๋ฉด ๊ฐ์ ์ค๋ ๋๋ฅผ ์์ฑํ์ฌ ๋ช
๋ น์ ์คํํ๋ค. ์ด์ ๋ฐ๋๋ก ํ๋ซํผ ์ค๋ ๋๋ฅผ ์์ฑํ ofPlatform() ๋ฉ์๋ ๋ํ ์ ๊ณตํ๋ฏ๋ก ์ฐธ๊ณ ํ๋๋ก ํ์.
/**
* current thread name: cooper virtual thread
* current thread is virtual: true
* Hello virtual Thread
*
* current thread name: cooper platform thread
* current thread is virtual: false
* Hello platform Thread
*/
public class Main {
public static void main(String[] args) throws Exception {
Runnable runnable = () -> {
System.out.println("current thread name: " + Thread.currentThread().getName());
System.out.println("current thread is virtual: " + Thread.currentThread().isVirtual());
final String threadType = Thread.currentThread().isVirtual() ? "virtual" : "platform";
System.out.printf("Hello %s Thread \n", threadType);
};
final Thread virtualThread = Thread.ofVirtual().name("cooper virtual thread").start(runnable);
Thread.sleep(1000);
final Thread platformThread = Thread.ofPlatform().name("cooper platform thread").start(runnable);
virtualThread.join();
platformThread.join();
}
}
์ค๋ ๋ ํ์ ๊ดํ ํฉํ ๋ฆฌ/์ ํธ๋ฆฌํฐ ๋ฉ์๋๋ฅผ ์ ๊ณตํ๋ Executors ํด๋์ค ๋ํ ๊ฐ์ ์ค๋ ๋๋ฅผ ์์ฑํ๋ ํฉํ ๋ฆฌ ๋ฉ์๋๋ฅผ ์ ๊ณตํ๋ค. ํฉํ ๋ฆฌ ๋ฉ์๋์ธ Executors.newVirtualThreadPerTaskExecutor() ์ submit(Runnable) ๋ฉ์๋๋ฅผ ํธ์ถํ ๋๋ง๋ค ์ ๊ฐ์ ์ค๋ ๋๋ฅผ ์์ฑํด ์์
์ ์คํํ๋ค.
์๋ ์์ ๋ ๊ฐ์ ์ค๋ ๋๋ฅผ ์คํํ๊ณ 5์ด๊ฐ ๋ธ๋กํน์ ํ์ ๋ ์คํ ์๊ฐ์ ํ์ธํ๋ ์ฝ๋์ด๋ค. ๊ธฐ์กด ํ๋ซํผ ์ค๋ ๋๋ ๊ฐ ์ค๋ ๋๊ฐ ๋ธ๋กํน์ผ๋ก ์ธํด OS ์ค๋ ๋๊น์ง ๋๊ธฐํ๊ธฐ ๋๋ฌธ์ ์คํ ์๊ฐ์ด ๊ธธ์ง๋ง, ๊ฐ์ ์ค๋ ๋๋ ํด๋น ๊ฐ์ ์ค๋ ๋๋ฅผ ๋ธ๋กํนํ์ง๋ง ๋ค๋ฅธ ๊ฐ์ ์ค๋ ๋๋ ์บ๋ฆฌ์ด ์ค๋ ๋์ ์ํด ๋ช
๋ น์ ์คํํ์ฌ ์ฝ 5์ด์ ๊ฐ๊น์ด ์์ ์๊ฐ์ผ๋ก ์คํ์ด ์๋ฃ๋์๋ค. ์ด๋ฅผ ํตํด I/O bound ๊ฐ ๋์ ์ฐ์ฐ์ ์๋ฒ์ ๋์ ์ฒ๋ฆฌ ์ฑ๋ฅ์ ๊ธฐ๋ํ ์ ์๋ค.
/*
* elapsed time = 5025ms
*/
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Main {
public static void main(String[] args) throws Exception {
final long startTime = System.currentTimeMillis();
try (final ExecutorService executorService = Executors.newVirtualThreadPerTaskExecutor()) {
for (int i = 0; i < 1000; i++) {
executorService.submit(() -> {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
});
}
}
final long endTime = System.currentTimeMillis();
System.out.println("elapsed time = " + (endTime - startTime) + "ms");
}
}
(2) ์คํ๋ง์์ ์ฌ์ฉ ๋ฐฉ๋ฒ
์ฐธ๊ณ ๋ก 2023.11.23 ๋ถํฐ Spring Boot 3.2 ๊ฐ ์ ์ ๋ฆด๋ฆฌ์ฆ ๋๋ฉด์ Java21 ์ ์ง์ํ๋ค.
(์ฐธ๊ณ ๋ก Gradle ๋ฒ์ ์ 8.4 ๋ฒ์ ์ด์๋ถํฐ Java21 ์ ์ง์ํ๋ค.)
Spring Boot 3.2 ๋ถํฐ Tomcat ์ ์ฌ์ฉ์ ์์ฒญ์ virtual thread ๊ธฐ๋ฐ์ผ๋ก ์ฒ๋ฆฌ๊ฐ ๊ฐ๋ฅํ๋ค. ๊ธฐ์กด ํ๋ซํผ ์ค๋ ๋ ๊ธฐ๋ฐ์ผ๋ก ์์ฒญ์ ์ฒ๋ฆฌํ๋ ๋ฐฉ์์ ๊ฐ์ ์ค๋ ๋๋ฅผ ์์ฑํด ์ฌ์ฉ์ ์์ฒญ์ ์ฒ๋ฆฌํ๋ ๋ฐฉ์์ผ๋ก ๋ณ๊ฒฝํ ์ ์๋ค. ์คํ๋ง์์ ์ ๊ณตํ๋ spring.threads.virtual.enabled ํ๋กํผํฐ๋ฅผ ํตํด ๊ฐ๋จํ ์ค์ ์ด ๊ฐ๋ฅํ๋ค. ์ต์
์ true ๋ก ์ค์ ํ์ ๊ฒฝ์ฐ, ๊ฐ์ ์ค๋ ๋๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์์ฒญ์ ์ฒ๋ฆฌํ๋ ๋ฐฉ์์ผ๋ก ๋์ํ๋ค. (defaut ๋ false ์ด๋ค.)
spring:
threads:
virtual:
enabled: true
ํ์ง๋ง ํด๋น ์ต์
์ true ๋ก ์ค์ ์ ๊ดํด์๋ ๊ฒํ ๊ฐ ํ์ํด ๋ณด์ธ๋ค. kakaopay ์์ ์งํํ ์์ฒญ ์ค๋ ๋๋ฅผ ๊ฐ์ ์ค๋ ๋๋ก ์ ํ์ ์ํ ํ
์คํธ ๊ฒฐ๊ณผ๋ฅผ ๋ณด๋ฉด Back Pressure ๋ฏธ์ํ, ์ฆ์ GC๋ก ์ธํ ์ผ์์ ์๋ต ์ง์ฐ, synchronized ๋ก ์ธํ pinning ์ด์๋ก ์ธํด ๋น๋๊ธฐ I/O bound ์์
์ ํํด์ ๊ฐ์์ค๋ ๋๋ฅผ ์ ์ฉ์ ๊ฒฐ์ ํ๋ค.
(์ : VirtualThreadTaskExecutor)
import java.util.concurrent.Executor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.VirtualThreadTaskExecutor;
import org.springframework.core.task.support.TaskExecutorAdapter;
import org.springframework.scheduling.annotation.EnableAsync;
@EnableAsync
@Configuration
public class AsyncConfig {
private static final String ASYNC_THREAD_PREFIX = "virtual-thread-task-";
@Bean
public Executor someTaskExecutor() {
return new TaskExecutorAdapter(new VirtualThreadTaskExecutor(ASYNC_THREAD_PREFIX));
}
}
7. ํ๊ณ
์ด๋ฒ ๊ธ์์๋ ๊ฐ์ ์ค๋ ๋์ ๊ดํด ์ดํด๋ณด์๋ค.
๊ธฐ์กด ์๋ฐ์ ์ค๋ ๋ ๊ธฐ๋ฐ์ ์ค๊ณ ๋ฐฉ์์ ์ ์งํ๋ฉด์ ์ฑ๋ฅ ๊ฐ์ ์ ๊ธฐ๋ํ ์ ์๋ ๋ฐฉ๋ฒ์ผ๋ก ํ์ฉ ๊ฐ๋ฅํ ๊ฐ๋ ์ด๋ค.
์ฐ์ I/O bound ๊ฐ ๋ง์ API ์๋ฒ์์ ๋น๋๊ธฐ๋ก ์ฒ๋ฆฌํ์ ๋์ ํจ๊ณผ๊ฐ ๊ฐ์ฅ ํฌ๊ณ ํ์ ์์๋ ๋ง์ด ํ์ฉํ๊ณ ์๋ ๋ฐฉ์์ผ๋ก ํ์ ๋๋ค. ์ฐธ๊ณ ๋ก CPU bound ์์ ์์๋ ๊ฐ์ ์ค๋ ๋์ ํจ๊ณผ๊ฐ ํฌ์ง ์๊ธฐ ๋๋ฌธ์ I/O bound ์์ ์์ ๊ฒํ ํด๋ณผ๋งํ ์์์ด๋ค.
๊ฐ์ ์ค๋ ๋๊ฐ ๊ธฐ์กด ์๋ฐ ํจ๋ฌ๋ค์์์ ์ ์ ๋ณ๊ฒฝ์ผ๋ก ์ฑ๋ฅ ๊ฐ์ ์ ๊ธฐ๋ํ ์ ์๋ ๊ธฐ์ ์ด์ง๋ง ์์ ์ธ๊ธํ๋ฏ์ด ๊ธฐ์กด ํ๋ซํผ ์ค๋ ๋ ๊ธฐ๋ฐ์ผ๋ก ์ด์ํ๋ ์๋น์ค์ ๊ฐ์ ์ค๋ ๋๋ฅผ ๋์
ํ๊ธฐ ์ํด์๋ ์ถ๊ฐ์ ์ธ ๊ฒ์ฆ์ด ํ์ํด ๋ณด์ธ๋ค. ์๋ฐ ๊ฐ๋ฐ์ ์
์ฅ์์๋ ์ ๋ง ํฌ์์์ด๋ค. ๐
Reference
- [Naver D2] Virtual Thread์ ๊ธฐ๋ณธ ๊ฐ๋ ์ดํดํ๊ธฐ
- [LY] Java ๊ฐ์ ์ค๋ ๋, ๊น์ด ์๋ ์์ค ์ฝ๋ ๋ถ์๊ณผ ์๋ ์๋ฆฌ 1ํธ - ์์ฑ๊ณผ ์์
- [kakaopay] [Project Loom] Virtual Thread์ ๋ด(Spring)์ ์๋๊ฐ
- Virtual Thread๋ ๋ฌด์์ผ๊น? (1)
- [oracle] virtual thread
- [openJDK wiki] Loom
- [spring io] Embracing Virtual Threads
- [dev.java] Virtual Thread
'๐ programming-language > java' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
| ์๋ฐ์์ ๋์์ฑ์ ์ ๋ฐ์ํ ๊น? (4) | 2025.03.23 |
|---|---|
| Java Local Cache ๋น๊ตํ๊ธฐ (0) | 2025.03.09 |
| SerialVersionUID๋ฅผ ์ ์ธํด์ผ ํ๋ ์ด์ (0) | 2024.11.28 |
| ์๋ฐ ๋น๋๊ธฐ๋ก ์นดํ ์ฝ์ ์์ ๋ง๋ค๊ธฐ (0) | 2024.11.26 |
| ์ด๋ํฐ ํจํด(adapter pattern) (1) | 2024.07.09 |
