Virtual Thread ์€ ๋ฌด์—‡์ผ๊นŒ?

2025. 4. 10. 16:55ยท๐Ÿ“‚ programming-language/java

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 {
            //...
        }
    }
}

ref : https://github.com/openjdk/jdk21/blob/master/src/java.base/share/native/libjava/Thread.c#L39

 

[์Šค๋ ˆ๋“œ 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 ์‚ฌ์šฉ ์—ฌ๋ถ€๋ฅผ ๊ฒ€ํ† ํ•ด์•ผ ๊ณ ์ • ์ด์Šˆ ๋ฐœ์ƒ์„ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค.

PINNING ์œผ๋กœ ์ธํ•œ CPU ๊ฒฉ๋ฆฌ ๋„์‹ํ™”

 

(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 ์ด์ „ ๋ชจ๋‹ˆํ„ฐ๋ฝ ๊ตฌ์„ฑ

 
 
Java24 ๋ถ€ํ„ฐ synchronized ๋ฉ”์„œ๋“œ/๋ธ”๋ก ๋‚ด์—์„œ ๋ธ”๋กœํ‚น๋˜๋Š” ๊ฐ€์ƒ ์Šค๋ ˆ๋“œ๊ฐ€ ํ”Œ๋žซํผ ์Šค๋ ˆ๋“œ๋ฅผ ํ•ด์ œํ•  ์ˆ˜ ์žˆ๋„๋ก JVM ์„ ๊ฐœ์„ ํ–ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๊ฐ€์ƒ ์Šค๋ ˆ๋“œ๊ฐ€ ์บ๋ฆฌ์–ด ์Šค๋ ˆ๋“œ์— ๊ณ ์ •(pinned) ๋˜๋Š” ์ƒํ™ฉ์„ ์ œ๊ฑฐํ•˜๊ณ  ๋™๊ธฐํ™”๋ฅผ ๊ณ ๋ คํ•ด์•ผ ํ•˜๋Š” ์ƒํ™ฉ์—์„œ ๊ฐ€์ƒ ์Šค๋ ˆ๋“œ์˜ ๋™์‹œ ์‹คํ–‰์ด ๊ฐ€๋Šฅํ•ด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ํ™•์žฅ์„ฑ์ด ํ–ฅ์ƒ๋˜์—ˆ๋‹ค. ๋˜ํ•œ, ๊ธฐ์กด Java ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ˆ˜์ • ์—†์ด, ๊ฐ€์ƒ ์Šค๋ ˆ๋“œ์™€ syncrhonized ์˜ ํ˜ธํ™˜์„ฑ์ด ํ™•๋ณด๋˜์–ด ๊ธฐ์กด์— ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ๊ด€ํ•œ ๊ณ ๋ฏผ์ด ํ˜„์ €ํžˆ ์ค„์–ด๋“ค์—ˆ๋‹ค.

Java24 ์ดํ›„ ๋ชจ๋‹ˆํ„ฐ๋ฝ ๊ตฌ์„ฑ

 
ํ•˜์ง€๋งŒ ์‹ค์ œ ์šด์˜ ํ™˜๊ฒฝ์—์„œ Java24 ์˜ ๊ฐœ์„ ์‚ฌํ•ญ์„ ๋„์ž…ํ•˜๋Š” ๊ฒƒ์€ ๊ณ ๋ฏผ์ด ํ•„์š”ํ•˜๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ ์šด์˜ ์•ˆ์ •์„ฑ์„ ์œ„ํ•ด์„œ ์ฃผ๋กœ LTS (Long Term Support) Version ์„ ์‚ฌ์šฉํ•œ๋‹ค. ์•„์‰ฝ๊ฒŒ๋„ Java24 ๋Š” LTS ๊ฐ€ ์•„๋‹ˆ๋ฏ€๋กœ ํ•ด๋‹น ๋ฒ„์ „์„ ๋„์ž…ํ•˜๋Š” ๊ฒƒ์€ ์‹œ๊ธฐ์ƒ์กฐ์ด๋‹ค. oracle read map ์„ ํ™•์ธํ•ด๋ณด๋ฉด 2025.09 ์— LTS ์ธ Java 25๊ฐ€ ์ถœ์‹œ ์˜ˆ์ •์ด๋ฏ€๋กœ ํ•ด๋‹น ๊ฐœ์„ ์‚ฌํ•ญ ์ ์šฉ์„ ์œ„ํ•ด์„œ๋Š” Java25 ๋„์ž…์„ ๊ณ ๋ฏผํ•ด๋ณด๋ฉด ์ข‹์„ ๋“ฏํ•˜๋‹ค.

ref : https://www.oracle.com/kr/java/technologies/java-se-support-roadmap.html

 

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
'๐Ÿ“‚ programming-language/java' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€
  • ์ž๋ฐ”์—์„œ ๋™์‹œ์„ฑ์€ ์™œ ๋ฐœ์ƒํ• ๊นŒ?
  • Java Local Cache ๋น„๊ตํ•˜๊ธฐ
  • SerialVersionUID๋ฅผ ์„ ์–ธํ•ด์•ผ ํ•˜๋Š” ์ด์œ 
  • ์ž๋ฐ” ๋น„๋™๊ธฐ๋กœ ์นดํŽ˜ ์ฝ˜์†” ์˜ˆ์ œ ๋งŒ๋“ค๊ธฐ
cooper25
cooper25
  • cooper25
    dev cooper
    cooper25
  • ์ „์ฒด
    ์˜ค๋Š˜
    ์–ด์ œ
    • ๋ถ„๋ฅ˜ ์ „์ฒด๋ณด๊ธฐ (84)
      • ๐Ÿ“‚ backend (34)
        • spring (19)
        • architecture (10)
        • test (5)
      • ๐Ÿ“‚ computer-science (5)
      • ๐Ÿ“‚ programming-language (12)
        • java (12)
      • ๐Ÿ“‚ infra (9)
        • mysql (4)
        • redis (2)
        • message-queue (3)
      • ๐Ÿ“‚ cloud (2)
        • aws (2)
      • ๐Ÿ“‚ frontend (1)
        • react (0)
      • ๐Ÿ“‚ education & lecture (16)
        • ์ธํ”„๋ผ ๊ณต๋ฐฉ (11)
        • ํ•ญํ”Œ ๋ฐฑ์—”๋“œ 7๊ธฐ (5)
      • ๐Ÿ“‚ ai (1)
        • claude (1)
      • ๐Ÿ“‚ etc (2)
        • ํšŒ๊ณ  (1)
        • ์ปจํผ๋Ÿฐ์Šค (1)
  • ๋ธ”๋กœ๊ทธ ๋ฉ”๋‰ด

    • ํ™ˆ
    • ํƒœ๊ทธ
    • ๋ฐฉ๋ช…๋ก
  • ๋งํฌ

  • ๊ณต์ง€์‚ฌํ•ญ

  • ์ธ๊ธฐ ๊ธ€

  • ํƒœ๊ทธ

    spring-batch
    spring camp 2025
    JPA
    ๋™์‹œ์„ฑ
    spring AOP
    spring
    ํšŒ๊ณ 
    react
    gof
    AWS
    kafka
    ์Šคํ”„๋ง์บ ํ”„ ํ›„๊ธฐ
    ๊ฐ€์ƒ ๋ฉด์ ‘ ์‚ฌ๋ก€๋กœ ๋ฐฐ์šฐ๋Š” ๋Œ€๊ทœ๋ชจ ์„ค๊ณ„
    mysql
    ๋ฐ์ดํ„ฐ ์ค‘์‹ฌ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์„ค๊ณ„
    nGrinder
    UUID
    ์ธํ”„๋ผ๊ณต๋ฐฉ
    Redisson
    ํ•ญํ•ดํ”Œ๋Ÿฌ์Šค
  • ์ตœ๊ทผ ๋Œ“๊ธ€

  • ์ตœ๊ทผ ๊ธ€

  • hELLOยท Designed By์ •์ƒ์šฐ.v4.10.6
cooper25
Virtual Thread ์€ ๋ฌด์—‡์ผ๊นŒ?
์ƒ๋‹จ์œผ๋กœ

ํ‹ฐ์Šคํ† ๋ฆฌํˆด๋ฐ”