[Java] ๊ฐ€์ƒ ์Šค๋ ˆ๋“œ (Virtual Thread) ํ›‘์–ด๋ณด๊ธฐ

๋ฐ˜์‘ํ˜•

Java์˜ Thread๋ฅผ ๋ณด๋ฉด ๋Š˜์ƒ ๊ณ ๋ฏผ์ด์—ˆ๋˜ ๋ถ€๋ถ„์ด ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. Java์˜ Thread API๋Š” ์šด์˜์ฒด์ œ์˜ ์Šค๋ ˆ๋“œ์™€ 1:1๋กœ ๋งคํ•‘๋˜์–ด ์žˆ์–ด ์“ธ ๋•Œ๋งˆ๋‹ค ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ์œผ๋กœ ์ธํ•œ ๋น„์šฉ ๋ฌธ์ œ๊ฐ€ ๊ฑธ๋ฆผ๋Œ์ด๊ณ , ์„œ๋ฒ„๋ฅผ ๊ฐœ๋ฐœํ•˜๋Š” ์ž…์žฅ์—์„œ ๋Œ€์šฉ๋Ÿ‰ ํŠธ๋ž˜ํ”ฝ์˜ ๋ฐœ์ƒ์„ ๊ณ ๋ คํ•ด์•ผ ํ•œ๋‹ค๋ฉด ์Šค์ผ€์ผ ์•„์›ƒ์„ ํ•ด์•ผํ• ์ง€ ๋ฆฌ์•กํ‹ฐ๋ธŒ ํ”„๋กœ๊ทธ๋ž˜๋ฐ(Reactive Programming)์„ ํ•ด์•ผํ• ์ง€ ์„ ํƒ์˜ ๊ณ ๋ฏผ์— ํœฉ์‹ธ์ด๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

 

๊ฐœ๋ฐœ์ž ์ž…์žฅ์—์„œ ๊ฐ€์žฅ ์‰ฝ๊ฒŒ ์ƒ๊ฐํ•œ๋‹ค๋ฉด ์Šค์ผ€์ผ ์•„์›ƒ์ผ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์š”์ƒˆ๋Š” ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค(k8s)์™€ ๊ฐ™์€ ์ปจํ…Œ์ด๋„ˆ ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜ ์‹œ์Šคํ…œ ๋‚ด์ง€ ํด๋ผ์šฐ๋“œ์—์„œ ์˜คํ†  ์Šค์ผ€์ผ๋ง ๊ธฐ๋Šฅ์„ ์ž˜ ์ง€์›ํ•˜๊ณ  ์žˆ์–ด ํŠธ๋ž˜ํ”ฝ์ด ๋Œ€๋Ÿ‰์œผ๋กœ ๋ฐœ์ƒํ•ด๋„ ์ž๋™์œผ๋กœ ์Šค์ผ€์ผ ์•„์›ƒํ•˜์—ฌ ํŠธ๋ž˜ํ”ฝ ๋ฐœ์ƒ์„ ์กฐ์ ˆํ•ด์ฃผ๋‹ˆ ๊ฐ€์žฅ ํŽธํ•œ ๋ฐฉ๋ฒ•์ด์ง€์š”. ํ•˜์ง€๋งŒ ์ด๋Š” ์—ฌ์ „ํžˆ ๋‚ด๊ฐ€ ์šด์˜ํ•˜๋Š” ์„œ๋น„์Šค์˜ ํ•˜๋“œ์›จ์–ด๋ฅผ ์ ์ ˆํžˆ ์‚ฌ์šฉํ•˜์ง€ ๋ชปํ•œ๋‹ค๋Š” ๋ฌธ์ œ๊ฐ€ ๋‚จ์•„ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. 

 

๊ทธ๋Ÿฌ๋ฉด ๋ฆฌ์•กํ‹ฐ๋ธŒ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์€ ์–ด๋–จ๊นŒ? ๋ฆฌ์•กํ‹ฐ๋ธŒ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์€ Thread๊ฐ€ ๊ฐ€์ง„ ํ•œ ์š”์ฒญ๋‹น ํ•œ ์Šค๋ ˆ๋“œ(Thread per request) ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ์š”์†Œ๊ธด ํ•˜์ง€๋งŒ ๊ทธ๋ฅผ ์œ„ํ•ด์„œ๋Š” ์—ฌ๋Ÿฌ ๊ฐ€์ง€ ๊ณ ๋ฏผํ•ด์•ผ ํ•  ๋ถ€๋ถ„์ด ๋งŽ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

 

  • ํ•จ์ˆ˜ ์ƒ‰ ๋ฌธ์ œ (Colored Function Problem)
  • ๋ณต์žกํ•œ ์ฝ”๋“œ ์Šคํƒ€์ผ
  • ๊ธฐ์กด ์Šคํƒ€์ผ๊ณผ ๋‹ค๋ฅธ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ํ…Œํฌ๋‹‰

ํ•œ ๋ฒˆ ์ฏค ๋ฆฌ์•กํ‹ฐ๋ธŒ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ํ•ด๋ดค๋‹ค๋ฉด ์•„์‹œ๊ฒ ์ง€๋งŒ ๋ฆฌ์•กํ‹ฐ๋ธŒ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ํ•˜๋ ค๋ฉด ๊ธฐ์กด์˜ ์Šค๋ ˆ๋“œ ์Šคํƒ€์ผ๊ณผ๋Š” ๋‹ค๋ฅธ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋ฌธ๋ฒ•์„ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๊ณ , ๋‚ด๊ฐ€ ์‚ฌ์šฉํ•˜๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ๋ฆฌ์•กํ‹ฐ๋ธŒํ•˜๊ฒŒ ๋™์ž‘ํ•˜๋Š” ํ•จ์ˆ˜๋“ค์ด์–ด์•ผ ํ•˜๋ฉฐ ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ์ด๋ฅผ ๋ฆฌ์•กํ‹ฐ๋ธŒ ์Šคํƒ€์ผ๋กœ ๋ฆฌํŒฉํ† ๋งํ•˜์—ฌ ์‚ฌ์šฉํ•˜๋Š” ๋“ฑ์˜ ๋ฒˆ๊ฑฐ๋กœ์›€์ด ๋งŽ์•„์ง‘๋‹ˆ๋‹ค. 

 

๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ๋ฆฌ์•กํ‹ฐ๋ธŒ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์€ ๊ธฐ์กด์˜ ์ž๋ฐ” ์Šค๋ ˆ๋“œ ์Šคํƒ€์ผ์ฒ˜๋Ÿผ ์ˆœ์ฐจ์ ์ธ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ํ…Œํฌ๋‹‰์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ , ์ฒด์ธ์„ ์ด์šฉํ•˜์—ฌ ์ด๋ฆฌ์ €๋ฆฌ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌํ•˜๊ณ , ๋ณด๋‚ด๊ณ , ํ•˜๋Š” ๋“ฑ์˜ ์ž‘์—…์„ ๋ฐ˜๋ณตํ•˜๊ฒŒ ๋˜๊ธฐ ๋•Œ๋ฌธ์— ๋ฆฌ์•กํ‹ฐ๋ธŒ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ์ฒ˜์Œํ•œ๋‹ค๋ฉด ๊ทธ๋งŒํผ ๋ฐฐ์›Œ์•ผํ•˜๋Š” ๊ธฐ์ˆ ์ด ๋งŽ์•„์ง€๊ณ  ์ฝ”๋“œ ์ •๋ฆฌ๋„ ์–ด๋ ค์›Œ์ง‘๋‹ˆ๋‹ค.

 

 

 

Virtual Thread

๊ทธ๋Ÿฌ๋˜ ์ค‘ ์ €๋Š” OpenJDK ๋‚ด์—์„œ ์ง„ํ–‰๋˜๋Š” ๋™์‹œ์„ฑ ์ฒ˜๋ฆฌ ๊ด€๋ จ ํ”„๋กœ์ ํŠธ๋ฅผ ๋ณด๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฆ„์€ Project Loom์ด์—ˆ๊ณ , JDK 19์—์„œ ์ฒ˜์Œ ๋“ฑ์žฅํ•˜์—ฌ ๊ตฌ์กฐ์  ๋™์‹œ์„ฑ, ๊ฐ€์ƒ ์Šค๋ ˆ๋“œ, ์ง€์ • ๋ฒ”์œ„ ๊ฐ’์ด๋ผ๋Š” ์„ธ ๊ฐ€์ง€ ๊ฐœ์„  ๋ฐฉ์•ˆ์„ ์ œ์•ˆํ•ฉ๋‹ˆ๋‹ค.

 

Project Loom
๊ธฐ์กด์˜ Thread API๊ฐ€ ์šด์˜์ฒด์ œ์˜ ์Šค๋ ˆ๋“œ๋ฅผ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์— ๋Œ€ํ•ด ํ˜„๋Œ€ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์ ์œผ๋กœ ๋ฆฌ์†Œ์Šค๊ฐ€ ๋งŽ์ด ์†Œ๋ชจ๋œ๋‹ค ํŒ๋‹จํ•˜์—ฌ ์ตœ์ ํ™” ์ง„ํ–‰์„ ์œ„ํ•ด ์‹œ์ž‘๋œ Java ๋‚ด ํ”„๋กœ์ ํŠธ๋กœ Java 21 ๋ฒ„์ „์—์„œ ๊ฐ€์ƒ ์Šค๋ ˆ๋“œ ๊ตฌํ˜„์ฒด๊ฐ€ ์ตœ์ดˆ๋กœ ๋“ฑ์žฅํ•จ.

 

Java 21์ด ๋“ฑ์žฅํ•œ ์ง€๊ธˆ, ๊ฐ€์ƒ ์Šค๋ ˆ๋“œ๋Š” Preview๊ฐ€ ์•„๋‹Œ ๊ณต์‹ ๊ธฐ๋Šฅ์œผ๋กœ ๋“ฑ์žฅํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ๊ฐ€์ƒ ์Šค๋ ˆ๋“œ๋Š” ์œ„์—์„œ ์–ธ๊ธ‰ํ–ˆ๋‹ค์‹œํ”ผ ๊ธฐ์กด์˜ ์Šค๋ ˆ๋“œ์˜ ์„ฑ๋Šฅ์„ ๊ฐœ์„ ํ•˜๊ธฐ ์œ„ํ•œ ์ž๋ฐ”์˜ ์ƒˆ๋กœ์šด API์ด๋ฉฐ ์ด ๊ธฐ๋Šฅ์˜ ๋ชฉ์ ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

 

  • ์š”์ฒญ๋‹น ์Šค๋ ˆ๋“œ ํ•œ ๊ฐœ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์„œ๋ฒ„ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ตœ์ ํ™”
  • ๊ธฐ์กด Thread API๋ฅผ ์ตœ์†Œํ•œ์˜ ๋ณ€๊ฒฝ๋งŒ์œผ๋กœ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜
  • ๊ธฐ์กด JDK ๋„๊ตฌ๋กœ ๊ฐ€์ƒ ์Šค๋ ˆ๋“œ ๋””๋ฒ„๊น…, ํ”„๋กœํŒŒ์ผ๋ง ๊ฐ€๋Šฅ

์œ„ ๋ชฉ์ ์€ JEP425: Virtual Threads ์—์„œ ์ฐธ๊ณ ํ•˜์˜€์œผ๋ฉฐ ์ด๋ฅผ ๋ณด์•„ ๊ฐ€์ƒ ์Šค๋ ˆ๋“œ๋Š” ์š”์ฒญ ํ•œ ๊ฐœ๋‹น ์Šค๋ ˆ๋“œ ํ•˜๋‚˜๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ธฐ์กด Thread API๋ฅผ ๋Œ€์ฒดํ•˜๊ธฐ ์œ„ํ•ด ๊ณ ์•ˆํ•œ ๊ฒƒ์œผ๋กœ ์ด๋ฒคํŠธ ๋ฃจํ”„๋ฅผ ์‚ฌ์šฉํ•œ ๋น„๋™๊ธฐ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด์— ๋Œ€์‘ํ•˜๊ธฐ ์œ„ํ•ด ๋‚˜์˜จ ๊ฒƒ์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค.

 

๊ทธ๋ ‡๋‹ค๋ฉด ๊ธฐ์กด Thread์™€ Virtual Thread๋Š” ์–ด๋– ํ•œ ์ฐจ์ด๊ฐ€ ์žˆ๋Š” ๊ฒƒ์ผ๊นŒ์š”?

 

 

 

Virtual Thread vs Platform Thread

Java 21์—์„œ๋Š” ์Šค๋ ˆ๋“œ ๊ฐœ๋…์ด ๋‘ ๊ฐ€์ง€ ๋“ฑ์žฅํ•˜๋ฉด์„œ ๊ธฐ์กด์˜ ์Šค๋ ˆ๋“œ๋ฅผ ํ”Œ๋žซํผ ์Šค๋ ˆ๋“œ(Platform Thread), ๊ฐ€์ƒ ์Šค๋ ˆ๋“œ(Virtual Thread)๋กœ ๋ช…๋ช…ํ•˜์˜€์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์ด ๊ธ€์—์„œ๋„ ๊ฐ€์ƒ ์Šค๋ ˆ๋“œ์™€ ํ”Œ๋žซํผ ์Šค๋ ˆ๋“œ๋ผ๋Š” ์šฉ์–ด๋กœ ๊ตฌ๋ถ„ํ•˜์—ฌ ์‚ฌ์šฉํ•  ๊ฒƒ์ด๋ฉฐ ๋น„๊ต๋ฅผ ์œ„ํ•ด ๋จผ์ € ํ”Œ๋žซํผ ์Šค๋ ˆ๋“œ๊ฐ€ ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ–ˆ๋Š”์ง€ ๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

 

 

ํ”Œ๋žซํผ ์Šค๋ ˆ๋“œ๋Š” TaskExecutor ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์Šค๋ ˆ๋“œ ํ’€(Thread Pool)์„ ์‚ฌ์šฉํ•˜์—ฌ ์‚ฌ์šฉํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ–ˆ์„ ๋•Œ ํ•˜๋‚˜์˜ ํƒœ์Šคํฌ๋‹น ํ•˜๋‚˜์˜ ์Šค๋ ˆ๋“œ๋ฅผ ํ• ๋‹นํ•˜์—ฌ ์ž‘์—…ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์•„์‹œ๋‹ค์‹œํ”ผ ํ”Œ๋žซํผ ์Šค๋ ˆ๋“œ๋Š” ๊ธฐ์กด์˜ Thread API๋กœ, ์šด์˜์ฒด์ œ ์Šค๋ ˆ๋“œ๋ฅผ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋งŽ์€ ๋น„์šฉ์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

 

 

๊ฐ€์ƒ ์Šค๋ ˆ๋“œ์—์„œ๋Š” ์ด๋ฅผ ๊ฐœ์„ ํ•˜๊ธฐ ์œ„ํ•ด ํ”Œ๋žซํผ ์Šค๋ ˆ๋“œ๋ฅผ ์บ๋ฆฌ์–ด ์Šค๋ ˆ๋“œ(Carrier Thread)๋กœ ์ •์˜ํ•˜์—ฌ ๋‚ด๋ถ€์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๋‹จ์ผ ํ”Œ๋žซํผ ์Šค๋ ˆ๋“œ์™€ ๊ทธ ์šฉ์–ด๋ฅผ ๋ถ„๋ฆฌํ–ˆ์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ VirtualThreadBuilder ๊ฐ์ฒด๊ฐ€ ์ž‘์—…์„ ๋ฐ›์•˜์„ ๋•Œ ๊ฐ€์ƒ ์Šค๋ ˆ๋“œ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ํ•ด๋‹น ์Šค๋ ˆ๋“œ๊ฐ€ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ์ž‘์—…์€ ForkJoinPool์ด๋ผ๋Š” ์บ๋ฆฌ์–ด ์Šค๋ ˆ๋“œ ํ’€์ด ๋ฐ›์•„ ๊ฐ ์บ๋ฆฌ์–ด ์Šค๋ ˆ๋“œ์— ํ• ๋‹นํ•˜๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค.

 

ForkJoinPool
ExecutorService์ฒ˜๋Ÿผ Thread Pool์„ ์ƒ์„ฑํ•˜์—ฌ ์—ฌ๋Ÿฌ ์ž‘์—…์„ ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌํ•ด์ฃผ๋„๋ก ํ•˜๋Š” ๊ฐ์ฒด๋กœ ExecutorService์™€๋Š” ๋‹ฌ๋ฆฌ, Task ํฌ๊ธฐ์— ๋”ฐ๋ผ ๋ถ„ํ• (Fork)ํ•˜์—ฌ ํ•ด๋‹น Task์˜ ๋งˆ์ง€๋ง‰ ๋ถ€๋ถ„์ด ์ฒ˜๋ฆฌ๋˜๋ฉด ์ด๋ฅผ ํ•ฉ์ณ(Join) ๋ฆฌํ„ดํ•˜๋Š” ๋ถ„ํ•  ์ •๋ณต ์•Œ๊ณ ๋ฆฌ์ฆ˜์œผ๋กœ ๋™์ž‘ํ•จ ๊ฐ€์ƒ ์Šค๋ ˆ๋“œ ์Šค์ผ€์ค„๋ง์„ ์œ„ํ•ด ์‚ฌ์šฉํ•˜๋Š” ForkJoinPool์€ ๊ธฐ์กด ForkJoinPool๊ณผ ์•ฝ๊ฐ„ ๋‹ค๋ฅธ ํ˜•ํƒœ๋ฅผ ์ง€๋‹ˆ๊ณ  ์žˆ์Œ

 

 

์ด ๋•Œ ์ค‘์š”ํ•œ ๊ฑด ์บ๋ฆฌ์–ด ์Šค๋ ˆ๋“œ๋Š” ํ”Œ๋žซํผ ์Šค๋ ˆ๋“œ์—์„œ I/O Blocking ๋œ ์ž‘์—…์„ ํ์— ์Œ“์•„ ์šฐ์„ ์ˆœ์œ„๋Œ€๋กœ ์ž‘์—…ํ•œ๋‹ค๋Š” ํŠน์ง•์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค๋Š” ์ ์ž…๋‹ˆ๋‹ค. ์บ๋ฆฌ์–ด ์Šค๋ ˆ๋“œ๋ณ„๋กœ ๊ฐ ๋ฆฌ์†Œ์Šค์— ๋”ฐ๋ผ 3~4๊ฐœ ์ •๋„ ๋ถ€์—ฌํ•˜์—ฌ ํ”Œ๋žซํผ ์Šค๋ ˆ๋“œ ์‚ฌ์šฉ ๋น„์œจ๊ณผ ์ปจํ…์ŠคํŠธ ์Šค์œ„์นญ ๋น„์šฉ์„ ๋‚ฎ์ถ”๋ฉด์„œ ์„ฑ๋Šฅ์„ ๊ฐœ์„ ํ•ฉ๋‹ˆ๋‹ค.

 

๋งŽ์€ ์ž‘์—…์„ ํ์— ๋„ฃ์„ ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— ๋งŽ์€ ์ง€์—ฐ์‹œ๊ฐ„์ด ๋ฐœ์ƒํ•˜๋Š” ๊ณณ์—์„œ๋Š” ์˜คํžˆ๋ ค ํ”Œ๋žซํผ ์Šค๋ ˆ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ์„ฑ๋Šฅ์„ ์ €ํ•˜์‹œํ‚ค๋Š” ์—ญํšจ๊ณผ๋ฅผ ๋‚ด๊ธฐ ๋•Œ๋ฌธ์— ์•„๋ž˜์˜ ์ƒํ™ฉ์—์„œ๋Š” ์˜คํžˆ๋ ค ์ข‹์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

 

  • ์ฒ˜๋ฆฌ ์‹œ๊ฐ„์ด ์˜ค๋ž˜ ๊ฑธ๋ฆฌ๋Š” ์ž‘์—…(๋Œ€์šฉ๋Ÿ‰ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ)์—๋Š” ํ”Œ๋žซํผ ์Šค๋ ˆ๋“œ ์‚ฌ์šฉ์ด ์ ์ ˆ
  • Java Stream API๋ฅผ ๋Œ€์ฒดํ•˜๊ณ ์ž ํ•˜๋Š” ์ž‘์—…์ด ์•„๋‹ˆ๋ฏ€๋กœ ํ•ด๋‹น ์ฝ”๋“œ๊ฐ€ ํฌํ•จ๋œ ์ž‘์—…์€ ํ”Œ๋žซํผ ์Šค๋ ˆ๋“œ ์‚ฌ์šฉ์ด ์ ์ ˆ

 

์บ๋ฆฌ์–ด ์Šค๋ ˆ๋“œ์— ํฌํ•จ๋œ ์ž‘์—… ํ์— ๋Œ€ํ•ด ์ข€ ๋” ์„ค๋ช…ํ•˜์ž๋ฉด ํ•ด๋‹น ์ž‘์—…๋“ค์€ FIFO ๋ฐฉ์‹์œผ๋กœ ์Šค์ผ€์ค„๋งํ•˜๋ฉฐ JVM ๋‚ด์—์„œ ๊ฐ€์ƒ ์Šค๋ ˆ๋“œ์˜ ๊ฐฏ์ˆ˜๋Š” ํ”Œ๋žซํผ ์Šค๋ ˆ๋“œ์ฒ˜๋Ÿผ ์ œํ•œ์„ ๋‘์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๊ทธ ์ด์œ ๋Š” ๊ฐ€์ƒ ์Šค๋ ˆ๋“œ์˜ ์ƒ์„ฑ ๋น„์šฉ(1KB)์ด ํ”Œ๋žซํผ ์Šค๋ ˆ๋“œ ์ƒ์„ฑ ๋น„์šฉ(1MB)์— ๋น„ํ•ด ํ˜„์ €ํžˆ ๋‚ฎ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

 

๊ฐ€์ƒ ์Šค๋ ˆ๋“œ ์Šค์ผ€์ค„๋ง์„ ์œ„ํ•œ ์บ๋ฆฌ์–ด ์Šค๋ ˆ๋“œ ๊ฐฏ์ˆ˜ ๊ด€๋ฆฌ๋Š” ์•„๋ž˜์˜ JVM ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ํ†ตํ•ด ๊ด€๋ฆฌ๋ฉ๋‹ˆ๋‹ค.

 

  • jdk.virtualThreadScheduler.parallelism
  • jdk.virtualThreadScheduler.maxPoolSize
  • jdk.virtualThreadScheduler.minRunnable

 

parallelism์€ ๋™์‹œ ์ฒ˜๋ฆฌ ๊ฐฏ์ˆ˜๋ฅผ ์˜๋ฏธํ•˜๋ฉฐ ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ๊ธฐ๊ธฐ์˜ ์ตœ๋Œ€ ๊ฐ€์šฉ ์ฝ”์–ด ๊ฐฏ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์—ฌ๋Ÿฌ ๊ฐœ์˜ ์Šค๋ ˆ๋“œ๋ฅผ ๋™์‹œ์— ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐฏ์ˆ˜๋ฅผ ์ •ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. 

 

maxPoolSize๋Š” ์ตœ๋Œ€ ์บ๋ฆฌ์–ด ์Šค๋ ˆ๋“œ ํ’€ ๊ฐฏ์ˆ˜๋ฅผ ๋งํ•˜๋ฉฐ ๊ธฐ๋ณธ๊ฐ’์€ max(parallelism, 256)์ž…๋‹ˆ๋‹ค. 

 

minRunnable์€ ์ตœ์†Œ ์‹คํ–‰ ๊ฐ€๋Šฅํ•œ ๊ฐฏ์ˆ˜๋ฅผ ๋งํ•˜๋ฉฐ ๊ธฐ๋ณธ๊ฐ’์€ max(parallelism / 2, 1)์ž…๋‹ˆ๋‹ค. ๋ณดํŽธ์ ์œผ๋กœ ์ฝ”์–ด ๊ฐฏ์ˆ˜์˜ ์ ˆ๋ฐ˜ ์ •๋„๋ฅผ ์ตœ์†Œ ๋‹จ์œ„๋กœ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.

 

 

 

Virtual Thread Scheduling

๊ฐ€์ƒ ์Šค๋ ˆ๋“œ๋Š” ์–ด๋–ป๊ฒŒ I/O blocking ์ƒํƒœ๋ฅผ ์ œ์–ดํ•˜๋Š” ๊ฑธ๊นŒ์š”? ์œ„ ๊ธ€์„ ์‚ดํŽด๋ดค์„ ๋•Œ ์Šค์ผ€์ค„๋Ÿฌ๊ฐ€ ๊ฐ ์ž‘์—…์„ ์บ๋ฆฌ์–ด ์Šค๋ ˆ๋“œ๋กœ ์ „๋‹ฌํ•˜์—ฌ ์ˆ˜ํ–‰ํ•œ๋‹ค๋ฉด ๊ทธ๋“ค์ด I/O blocking ์ƒํƒœ์ธ์ง€๋ฅผ ๊ฐ€์ƒ ์Šค๋ ˆ๋“œ๋‚˜ ์ž‘์—…์„ ํ†ตํ•ด์„œ ์•Œ ์ˆ˜ ์žˆ์–ด์•ผ ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ด๋ฒˆ์—๋Š” ๊ฐ€์ƒ ์Šค๋ ˆ๋“œ๊ฐ€ ์–ด๋–ค์‹์œผ๋กœ ์ž‘์—…์„ ์ œ์–ดํ•˜๋Š”์ง€์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

 

 

๊ฐ€์ƒ ์Šค๋ ˆ๋“œ๋„ ์—ฌํƒ€ ์Šค๋ ˆ๋“œ์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ JVM์˜ ํž™(Heap) ์˜์—ญ์— ์ €์žฅ๋ฉ๋‹ˆ๋‹ค. ํž™์˜์—ญ์— ์ €์žฅ๋˜์—ˆ์„ ๋•Œ๋Š” ์ž‘์—…์ด ์ง„ํ–‰ ์ค‘์ธ ์ƒํƒœ๋กœ ์ง„ํ–‰ ์ค‘์— ์‚ฌ์šฉํ•œ ํ•จ์ˆ˜ ํ˜ธ์ถœ ์ •๋ณด, ๋ณ€์ˆ˜ ์ •๋ณด ๋“ฑ์ด ์—ฌ๊ธฐ์— ๋‹ด๊ธฐ๊ฒŒ ๋˜๊ณ , I/O blocking์ด ๋ฐœ์ƒํ•˜๋ฉด ์ด๋“ค์€ ์ž‘์—…ํ–ˆ๋˜ ์Šคํƒ ํ”„๋ ˆ์ž„(stack frames)์„ ๋ณ„๋„์˜ ํž™ ์˜์—ญ์— ์ž„์‹œ๋กœ ๋ณต์‚ฌํ•ด๋’€๋‹ค๊ฐ€ ์บ๋ฆฌ์–ด ์Šค๋ ˆ๋“œ๊ฐ€ ๋‹ค๋ฅธ ์ž‘์—… ์ˆ˜ํ–‰์‹œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์ž‘์—…์„ Mount/Unmount ์ž‘์—…์ด๋ผ ํ•ฉ๋‹ˆ๋‹ค. 

 

  • Mount: ๊ฐ€์ƒ ์Šค๋ ˆ๋“œ ๋‚ด ์ž‘์—…์ด ์บ๋ฆฌ์–ด ์Šค๋ ˆ๋“œ์—์„œ ์‹คํ–‰ ์ค‘์ธ ๊ฒฝ์šฐ
  • Unmount: ๊ฐ€์ƒ ์Šค๋ ˆ๋“œ ๋‚ด ์ž‘์—…์ด I/O blocking ๋“ฑ ์ƒํƒœ๋กœ ์บ๋ฆฌ์–ด ์Šค๋ ˆ๋“œ์—์„œ ์ž ์‹œ ์ค‘๋‹จ๋œ ๊ฒฝ์šฐ

์ด๋Ÿฌํ•œ ์ž‘์—…์ด ์ˆ˜ํ–‰๋˜๋Š” ๋™์•ˆ ๊ฐ€์ƒ ์Šค๋ ˆ๋“œ๋Š” ์ƒํƒœ๊ฐ€ ๋ณ€๊ฒฝ๋˜๋Š”๋ฐ, ๋Œ€ํ‘œ์ ์œผ๋กœ ๊ฐ€์ƒ ์Šค๋ ˆ๋“œ ์ž‘์—…์ด I/O blocking ๋“ฑ์— ์˜ํ•ด ์ผ์‹œ ์ •์ง€๋œ ๊ฒฝ์šฐ, PARKED ์ƒํƒœ๋กœ ์ „ํ™˜๋ฉ๋‹ˆ๋‹ค.

 

์œ„ ์ฝ”๋“œ๋Š” VirtualThread ํด๋ž˜์Šค์—์„œ ๊ฐ€์ ธ์˜จ ์‹ค์ œ ๊ฐ€์ƒ ์Šค๋ ˆ๋“œ๊ฐ€ ์‚ฌ์šฉํ•˜๋Š” ์ƒํƒœ๊ฐ’๋“ค์ž…๋‹ˆ๋‹ค. NEW ~ PARKED_SUSPEND๊นŒ์ง€ ์—ฌ๋Ÿฌ ์ข…๋ฅ˜๊ฐ€ ์žˆ์œผ๋ฉฐ ๊ทธ ์ค‘ ์ž์ฃผ ๋ณด์ด๋Š” ์ƒํƒœ๊ฐ’์€ RUNNABLE, RUNNING, PARKED, PINNED๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•˜์—ฌ ๊ฐ€์ƒ ์Šค๋ ˆ๋“œ๊ฐ€ ์ƒ์„ฑ๋˜์–ด ์ž‘์—…์ด ์ข…๋ฃŒ๋  ๋•Œ๊นŒ์ง€๋ฅผ ์ผ๋ จ์˜ ๊ณผ์ •์œผ๋กœ ๋ณด์ž๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

 

  • ํ•˜๋‚˜์˜ ์ž‘์—…์„ ๊ฐ€์ƒ ์Šค๋ ˆ๋“œ๋กœ ์ƒ์„ฑ ํ›„ ์บ๋ฆฌ์–ด ์Šค๋ ˆ๋“œ์— mount 
  • ํ•ด๋‹น ์š”์ฒญ ์ž‘์—…์— I/O blocking์ด ๋ฐœ์ƒํ•˜๋Š” ๊ฒฝ์šฐ ์Šคํƒ ํ”„๋ ˆ์ž„์„ ์ƒ์„ฑํ•˜๊ณ  ์บ๋ฆฌ์–ด ์Šค๋ ˆ๋“œ์—์„œ unmount
  • ์œ„ ์ž‘์—…์ด RUNNABLE ๋˜๋Š” ๋™์•ˆ ๋‹ค๋ฅธ ์ž‘์—…(๊ฐ€์ƒ ์Šค๋ ˆ๋“œ) ์‹คํ–‰
  • RUNNABLE ์ƒํƒœ๊ฐ€ ๋˜๋ฉด continue execution ๋ฉ”์„œ๋“œ์— ๋‚˜๋จธ์ง€ ์ž‘์—… ์‹คํ–‰
  • ์ž‘์—… ์ข…๋ฃŒ

์œ„ ๊ณผ์ •์€ ๊ฐ€์ƒ ์Šค๋ ˆ๋“œ๋ฅผ ์ด์šฉํ•˜์—ฌ ์ˆ˜ํ–‰ํ•œ ์ž‘์—…์ด ์„ฑ๊ณต์ ์œผ๋กœ ์ˆ˜ํ–‰ํ•˜์—ฌ ์ข…๋ฃŒ๋œ ๊ฒฝ์šฐ์˜ ๊ณผ์ •์ž…๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์Šค๋ ˆ๋“œ ์ž‘์—… ์ค‘ ๋„์ค‘์— ์‹คํŒจํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š” ์–ด๋–ป๊ฒŒ ๋ ๊นŒ์š”? 

 

 

 

Pinning

๊ฐ€์ƒ ์Šค๋ ˆ๋“œ๊ฐ€ ์บ๋ฆฌ์–ด ์Šค๋ ˆ๋“œ์—์„œ unmount ๋˜์ง€ ๋ชปํ•˜๊ณ  ์žˆ๋Š” ์ƒํƒœ๊ฐ’์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ PINNED ๋กœ ์ •์˜ํ•˜์˜€๋Š”๋ฐ, ๊ฐ€๋ น ๊ฐ€์ƒ ์Šค๋ ˆ๋“œ๊ฐ€ blocking ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ๋กœ ์ธํ•ด PARKING ์ƒํƒœ๊ฐ€ ๋˜๋ฉด ์บ๋ฆฌ์–ด ์Šค๋ ˆ๋“œ๋Š” ํ•ด๋‹น ์ž‘์—…์— ๋Œ€ํ•œ ์Šคํƒ ํ”„๋ ˆ์ž„์„ ํž™ ์˜์—ญ์— ์ €์žฅํ•ด๋†“๊ณ  ๋‹ค๋ฅธ ์ž‘์—…์„ ํ•˜๋Š” ๊ฒŒ ์ •์ƒ์ ์ธ ๋ฐฉํ–ฅ์ด์ง€๋งŒ ์ด ์ž‘์—…์ด ์ œ๋Œ€๋กœ ์ด๋ค„์ง€์ง€ ์•Š๋Š” ๊ฒฝ์šฐ PINNED ์ƒํƒœ๊ฐ€ ๋˜๋ฉฐ ์ด๋ฅผ ํ”ผ๋‹(PINNING)์ด๋ผ ํ•ฉ๋‹ˆ๋‹ค.

 

๊ทธ๋ ‡๋‹ค๋ฉด ํ”ผ๋‹์€ ์–ด๋– ํ•œ ๊ฒฝ์šฐ์— ๋ฐœ์ƒํ• ๊นŒ์š”?

 

  • ์ฝ”๋“œ ๋‚ด synchronized ๋ธ”๋ก ์‚ฌ์šฉ ๋ฐ ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ
  • native ๋ฉ”์„œ๋“œ ํ˜น์€ Java ์™ธ๋ถ€ ํ•จ์ˆ˜(Java ์™ธ ๋‹ค๋ฅธ ์–ธ์–ด๋กœ ๊ตฌํ˜„๋œ ํ•จ์ˆ˜)๋ฅผ ํ˜ธ์ถœ

๋งŒ์•ฝ ํ”Œ๋žซํผ ์Šค๋ ˆ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋™์‹œ์„ฑ ์ฒ˜๋ฆฌ๋ฅผ ๊ตฌํ˜„ํ–ˆ๋‹ค๋ฉด ๊ณ ๋ คํ•ด์•ผ ํ•  ๋ถ€๋ถ„ ์ค‘์— ํ•˜๋‚˜๋Š” ํ•˜๋‚˜์˜ ์ž์›์„ ๋‘๊ณ  ๋‘ ์Šค๋ ˆ๋“œ๊ฐ€ ๋™์‹œ์— ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์Ÿ ๋ฌธ์ œ์ž…๋‹ˆ๋‹ค. ์ด๋ฅผ ์œ„ํ•ด Java์—์„œ synchronized ๋ธ”๋ก์„ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๋‹ค. 

 

์ฝ”๋“œ๋ฅผ ์˜ˆ์‹œ๋กœ ๋“ค๋ฉด ์œ„์™€ ๊ฐ™์€ ์ฝ”๋“œ๋ฅผ ๋งํ•˜๋Š”๋ฐ, ๋‘ ์Šค๋ ˆ๋“œ๊ฐ€ ์„œ๋กœ ์—…๋ฐ์ดํŠธ๋ฅผ ํ•จ์œผ๋กœ์จ ์—…๋ฐ์ดํŠธ ์ˆœ๋ฒˆ์ด ๋’ค์—‰ํ‚ค๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๊ธฐ ๋•Œ๋ฌธ์— synchronized ๋ฉ”์„œ๋“œ๋กœ ์—…๋ฐ์ดํŠธํ•˜๋„๋ก ๊ตฌํ˜„ํ•œ ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค.

 

ํ•˜์ง€๋งŒ ๊ฐ€์ƒ ์Šค๋ ˆ๋“œ์—์„œ๋Š” ์ด๋Ÿฌํ•œ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ๊ฐ€์ƒ ์Šค๋ ˆ๋“œ์—์„œ blocking์ด ๋ฐœ์ƒํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹Œ ์บ๋ฆฌ์–ด ์Šค๋ ˆ๋“œ์—์„œ blocking์ด ๋ฐœ์ƒํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ž์นซํ•˜๋ฉด ๊ฐ€์ƒ ์Šค๋ ˆ๋“œ ์Šค์ผ€์ค„๋Ÿฌ์—์„œ ํ•ด๋‹น ์บ๋ฆฌ์–ด ์Šค๋ ˆ๋“œ๋ฅผ ๊ด€๋ฆฌํ•˜์ง€ ๋ชปํ•˜๊ฒŒ ๋˜๋Š” ํ˜„์ƒ์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ๊ณง ์„ฑ๋Šฅ ์ €ํ•˜๋กœ ์ด์–ด์ง€์ฃ .

 

์ด๋Ÿด ๋•Œ๋Š” ๋™๊ธฐ ๋ธ”๋ก/๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜๊ธฐ๋ณด๋‹ค๋Š” ReentrantLock๊ณผ ๊ฐ™์€ ์„ธ๋งˆํฌ์–ด๋ฅผ ์ด์šฉํ•˜์—ฌ ์บ๋ฆฌ์–ด ์Šค๋ ˆ๋“œ๋ฅผ blockingํ•˜์ง€ ์•Š๊ณ  ๊ฐ€์ƒ ์Šค๋ ˆ๋“œ๋ฅผ PARKED๋กœ ์œ ๋„ํ•˜๋Š” ๊ฒƒ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ฌธ์ œ๋Š” ๋ฒ„๊ทธ์— ํ•ด๋‹นํ•˜๋ฉฐ Java 21์—๋„ ๊ณ„์† ์กด์žฌํ•˜์ง€๋งŒ ์ฐจ๊ธฐ ๋ฒ„์ „์—์„œ ์ด๋ฅผ ์ˆ˜์ •ํ•œ๋‹ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

 

๋˜ํ•œ Java์—์„œ C/C++ ๊ณ„์—ด์˜ ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด JNI(Java Native Interface)๋ฅผ ์ด์šฉํ•˜๋Š”๋ฐ, ์ด๋ฅผ ํ†ตํ•ด ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ๋„ ํ”ผ๋‹์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ๋‹ค๋งŒ JNI์—์„œ๋„ isVirtualThread ๋ฉ”์„œ๋“œ๋ฅผ ์ง€์›ํ•˜์—ฌ ํ˜ธ์ถœํ•˜๋ ค๋Š” ์Šค๋ ˆ๋“œ๊ฐ€ ํ”Œ๋žซํผ ์Šค๋ ˆ๋“œ์ธ์ง€, ๊ฐ€์ƒ ์Šค๋ ˆ๋“œ์ธ์ง€์— ๋Œ€ํ•œ ๊ฐ’์„ ๋‚ด๋ ค์ฃผ๋ฏ€๋กœ ์ด๋ฅผ ํ†ตํ•ด์„œ ๊ฐœ์„ ํ•  ์ˆ˜๋Š” ์žˆ์–ด ๋ณด์ž…๋‹ˆ๋‹ค.

 

 

 

Thread Pooling

ํ”Œ๋žซํผ ์Šค๋ ˆ๋“œ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ๋Š” ๊ทธ ์ƒ์„ฑ ๋น„์šฉ์ด ํฌ๊ธฐ ๋•Œ๋ฌธ์— ์Šค๋ ˆ๋“œ๋ฅผ ๋ฏธ๋ฆฌ ์ƒ์„ฑํ•˜์—ฌ ์‚ฌ์šฉํ•  ๋•Œ๋งˆ๋‹ค ๋นผ์„œ ์“ฐ๊ธฐ ์œ„ํ•ด ํ’€๋ง(Pooling)์„ ์‚ฌ์šฉํ–ˆ์—ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ ‡๋‹ค๋ฉด ๊ฐ€์ƒ ์Šค๋ ˆ๋“œ๋„ ํ’€๋งํ•  ์ˆ˜ ์žˆ์„๊นŒ์š”?

 

Java ์—”์ง€๋‹ˆ์–ด๋“ค์€ ๊ฐ€์ƒ ์Šค๋ ˆ๋“œ๋ฅผ ํ’€๋งํ•˜์ง€๋งˆ๋ผ(Don't pool virtual threads!)๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ํ’€๋ง์€ ์šด์˜์ฒด์ œ ์Šค๋ ˆ๋“œ์™€ ๊ฐ™์€ ๊ณ ๊ฐ€์˜ ๋น„์šฉ์ด ๋“ค์–ด๊ฐ€๋Š” ๊ณณ์—์„œ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด ๊ณ ์•ˆ๋œ ๊ฒƒ์ธ๋ฐ, ๊ฐ€์ƒ ์Šค๋ ˆ๋“œ๋Š” ๊ทธ ๋ฆฌ์†Œ์Šค์˜ 1/10 ์ •๋„ ๋ฐ–์— ๋˜์ง€ ์•Š์œผ๋ฏ€๋กœ ํ’€๋งํ•˜์ง€ ์•Š์•„๋„ ๋œ๋‹ค๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

 

ํ•˜์ง€๋งŒ ํŠน์ • ๋ฉ”์„œ๋“œ์— ์‚ฌ์šฉํ•˜๋Š” ๊ฐ€์ƒ ์Šค๋ ˆ๋“œ ๊ฐฏ์ˆ˜๋ฅผ ์ œํ•œํ•˜๋Š” ๊ฑธ ๋ชฉ์ ์œผ๋กœ ํ•˜๊ณ  ์žˆ๋‹ค๋ฉด ์Šค๋ ˆ๋“œ ํ’€ ๋Œ€์‹  ์„ธ๋งˆํฌ์–ด ๊ธฐ๋ฒ•์œผ๋กœ ์ ‘๊ทผํ•ด ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

ํ”Œ๋žซํผ ์Šค๋ ˆ๋“œ์—์„œ๋Š” ์œ„์™€ ๊ฐ™์ด ExecutorService์˜ ๊ตฌํ˜„์ฒด์ธ newFixedThreadPool ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ์Šค๋ ˆ๋“œ ๊ฐฏ์ˆ˜๋ฅผ ๋ฐ›์•„ ์Šค๋ ˆ๋“œ๋ฅผ ๋ฏธ๋ฆฌ ์ƒ์„ฑํ•˜์—ฌ ์ƒ์š”ํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

 

ํ”ผ๋‹ ์ด์Šˆ์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์„ธ๋งˆํฌ์–ด ๊ธฐ๋ฒ•์„ ์ด์šฉํ•˜์—ฌ ํŠน์ • ๋ฉ”์„œ๋“œ์—์„œ ๊ฐ€์ƒ ์Šค๋ ˆ๋“œ ์ƒ์„ฑ ์ˆ˜๋ฅผ ์ œํ•œํ•ด ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์œ„ ์ฝ”๋“œ๋Š” ์ œํ•œ๋œ ์„ธ๋งˆํฌ์–ด๋ฅผ ์ƒ์„ฑํ•ด๋†“๊ณ , ํ˜ธ์ถœ๋งˆ๋‹ค ์นด์šดํŒ…์„ ํ•˜๋ฉฐ ํ˜ธ์ถœ์ด ์™„๋ฃŒ๋˜๋ฉด ๋‹ค์‹œ ๊ทธ ์นด์šดํŒ…์„ ๋ณต๊ตฌํ•˜๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค.

 

 

 

Scoped Value

๊ฐ€์ƒ ์Šค๋ ˆ๋“œ์—์„œ๋„ ํ”Œ๋žซํผ ์Šค๋ ˆ๋“œ์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ThreadLocal ๋ณ€์ˆ˜๊ฐ€ ์กด์žฌํ•ฉ๋‹ˆ๋‹ค. ์ž๋ฐ”์—์„œ ์ œ๊ณตํ•˜๋Š” ์Šค๋ ˆ๋“œ ๋กœ์ปฌ ๋ณ€์ˆ˜์—๋Š” ThreadLocal๊ณผ InheritableThreadLocal์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ, ๊ฐ€์ƒ ์Šค๋ ˆ๋“œ๋Š” ๊ณต์‹์ ์ธ ์Šค๋ ˆ๋“œ ํ’€๋ง์„ ์ง€์›ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ํ•˜๋“œ์›จ์–ด ๋ฆฌ์†Œ์Šค๋งŒํผ ์ตœ๋Œ€ํ•œ์˜ ๊ฐ€์ƒ ์Šค๋ ˆ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. (์›ํ•˜๋ฉด 1,000,000๊ฐœ ์ด์ƒ๊นŒ์ง€๋„...) 

 

ํ•˜์ง€๋งŒ ์ด๋Ÿด ๊ฒฝ์šฐ ์ˆ˜๋งŽ์€ ๊ฐ€์ƒ ์Šค๋ ˆ๋“œ๋“ค์ด ๊ณต์œ ๋œ ๋ฆฌ์†Œ์Šค์— ์ ‘๊ทผํ•˜๊ธฐ ์œ„ํ•ด ๊ณ„์† ๋Œ€๊ธฐํ•˜๊ฒŒ ๋˜๋Š”๋ฐ, ๋งŒ์•ฝ InheritableThreadLocal๊ณผ ๊ฐ™์ด ๋น„์šฉ์ด ๋น„์‹ผ ๋ฆฌ์†Œ์Šค์˜ ํ’€๋ง์„ ์ˆ˜ํ–‰ํ•˜๊ฒŒ ๋˜๋ฉด ๊ฐ€์ƒ ์Šค๋ ˆ๋“œ๊ฐ€ ์ฐจ์ง€ํ•˜๋Š” ๋ฉ”๋ชจ๋ฆฌ์˜ ํฌ๊ธฐ๊ฐ€ ๋” ์ปค์ง€๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

 

์ด๋Ÿฌํ•œ ๋ฌธ์ œ ๋•Œ๋ฌธ์— Java 20์—์„œ๋Š” JEP 429: Scoped Values (Incubator) ๊ฐ€ ๊ณ ์•ˆ๋˜์—ˆ์œผ๋ฉฐ ๊ฐ€์ƒ ์Šค๋ ˆ๋“œ ๋‚ด ํ˜น์€ ๊ฐ€์ƒ ์Šค๋ ˆ๋“œ ๊ฐ„์— ๊ณต์œ ํ•  ์ˆ˜ ์žˆ๋Š” ๋ถˆ๋ณ€ ๋ฐ์ดํ„ฐ ํด๋ž˜์Šค๋ฅผ ํ†ตํ•ด ThreadLocal์ด ๊ฐ€์ง„ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ณ ์ž ํ–ˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ThreadLocal์„ 100% ๋Œ€์ฒดํ•˜๊ธฐ ์œ„ํ•œ ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค.

 

์ฝ”๋“œ ์ž์ฒด์—๋Š” ํฐ ์ฐจ์ด๊ฐ€ ์—†์ง€๋งŒ ThreadLocal์€ ๊ฐ€๋ณ€์„ฑ, ScopedValue๋Š” ๋ถˆ๋ณ€์„ฑ์ด๋ผ๋Š” ์ ์— ์ฐจ์ด๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ThreadLocal์€ ์ปจํ…Œ์ด๋„ˆ ์ˆ˜๋ช…๊ณผ ๋™์ผํ•˜๊ฒŒ ๊ฐ€์ ธ๊ฐ€์„œ remove ๋ฉ”์„œ๋“œ๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ํ˜ธ์ถœํ•˜๊ฑฐ๋‚˜, ์ƒˆ๋กœ์šด ๊ฐ’์„ ์„ค์ •ํ•˜๋Š” ๋ฐฉ๋ฒ•์œผ๋กœ ๊ทธ ์ˆ˜๋ช…์„ ๊ฐฑ์‹ ํ•˜์ง€๋งŒ ScopedValue๋Š” ํ˜„์žฌ ์‚ฌ์šฉ ์ค‘์ธ ์Šค๋ ˆ๋“œ ์ˆ˜๋ช…์„ ๋”ฐ๋ผ๊ฐ€๊ณ , ๋ฉ”์„œ๋“œ๋กœ ๊ฐ’์„ ํ• ๋‹นํ•˜์ง€ ์•Š๊ณ  ์Šค์ฝ”ํ”„๋กœ ํ• ๋‹นํ•œ๋‹ค๋Š” ์ ์—์„œ Python์˜ yield์™€ ์•ฝ๊ฐ„ ์œ ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

 

 

 

๋งˆ์น˜๋ฉฐ..

์ด๋ฒˆ ํฌ์ŠคํŠธ์—์„œ๋Š” ๊ฐ€์ƒ ์Šค๋ ˆ๋“œ๋ฅผ ๊ฐ„๋‹จํ•˜๊ฒŒ ๋ณด๋‹ค๋Š” ์ข€ ๋” ๊นŠ๊ฒŒ ํ—ค์งš์–ด๋ณด๋ฉด์„œ ๊ฐ€์ƒ ์Šค๋ ˆ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด ๋ฐ˜๋“œ์‹œ ์•Œ์•„์•ผ ํ•  ๋ถ€๋ถ„์— ๋Œ€ํ•ด ์ค‘์ ์ ์œผ๋กœ ๋‹ค๋ค„๋ดค์Šต๋‹ˆ๋‹ค.

 

์ž๋ฐ”์—์„œ ๋น„๋™๊ธฐ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์€ ๊ฐ€์ƒ ์Šค๋ ˆ๋“œ๊ฐ€ ๋‚˜์˜ค๊ธฐ ์ด์ „์—๋Š” ๊ต‰์žฅํžˆ ์–ด๋ ค์šด ํŒจ๋Ÿฌ๋‹ค์ž„์œผ๋กœ ์•Œ๋ ค์ ธ ์žˆ์Šต๋‹ˆ๋‹ค. ์‚ฌ์šฉํ•˜๊ธฐ ์–ด๋ ค์šด Callable ๋ฐฉ์‹, ๊ฐœ๋ฐœ์ž๊ฐ€ ๋น„๋™๊ธฐ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์— ๋Œ€ํ•œ ๋งŽ์€ ์ง€์‹ ์š”๊ตฌ, ํ•จ์ˆ˜ ์ƒ‰ ๋ฌธ์ œ ๋“ฑ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•ด ๋งŽ์€ ๊ณ ๋ฏผ์„ ํ•ด์•ผ ํ•˜๊ณ , ๊ทธ๋งŒํผ ์žฅ๋ฒฝ์ด ๋†’์•˜์ง€๋งŒ ๊ฐ€์ƒ ์Šค๋ ˆ๋“œ์˜ ๋“ฑ์žฅ์œผ๋กœ ํ•จ์ˆ˜ ์ƒ‰ ๋ฌธ์ œ์™€ ๊ตฌ์กฐ์  ๋™์‹œ์„ฑ์„ ๋ถ€ํ™œ์‹œํ‚ด์œผ๋กœ์จ ๊ฐœ๋ฐœ์ž๊ฐ€ ์ข€ ๋” ์‚ฌ์šฉํ•˜๊ธฐ ์‰ฝ๊ฒŒ ํ•ด์ฃผ์—ˆ์ฃ .

 

์•„์ง ๊ตญ๋‚ด์—์„œ Java 21 ๋„์ž…์ด ๋งŽ์ด ๋œ ๊ณณ์€ ์—†์ง€๋งŒ ๊ฐ€์ƒ ์Šค๋ ˆ๋“œ๋ฅผ ํ†ตํ•ด ์•„์ง๊นŒ์ง€ Java ํ•œ์ž๋ฆฌ ์ˆ˜ ๋ฒ„์ „์— ๋จธ๋ฌผ๋Ÿฌ ๊ณ„์‹œ๋Š” ๋ถ„๋“ค๋„ ์ด๋ฒˆ ๊ธฐํšŒ์— ํฐ ๋ณ€ํ™”๋ฅผ ๊ฐ€์ ธ๋ณด๋Š” ๊ฒƒ์€ ์–ด๋–จ๊นŒ์š”?

 

 

์ฐธ๊ณ :

Oracle Tech Blog(https://blogs.oracle.com/javamagazine/post/java-loom-virtual-threads-platform-threads)

๋ฐ˜์‘ํ˜•
TAGS.

Tistory Comments