Community

๐Ÿ•Š๏ธ Java์˜ ExecutorService ์Šค๋ ˆ๋“œ ํ’€ ์ •๋ณตํ•˜๊ธฐ

์ด๋ฒˆ ๊ธ€์—์„œ๋Š” Executors๊ฐ€ ์ œ๊ณตํ•˜๋Š” ๋Œ€ํ‘œ์ ์ธ ์Šค๋ ˆ๋“œ ํ’€ 4์ข…๋ฅ˜๋ฅผ ์‚ดํŽด๋ณด๊ณ , ๊ฐ๊ฐ์˜ ์‚ฌ์šฉ ์‹œ๋‚˜๋ฆฌ์˜ค์™€ ์ฃผ์˜ํ•  ์ ์„ ์˜ˆ์ œ ์ค‘์‹ฌ์œผ๋กœ ์ •๋ฆฌํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ย  newFixedThreadPool(int nThreads) ์ด ๋ฉ”์„œ๋“œ๋Š” ์ •ํ•ด์ง„ ๊ฐœ์ˆ˜๋งŒํผ์˜ ์Šค๋ ˆ๋“œ๋ฅผ ๋ฏธ๋ฆฌ ์ƒ์„ฑํ•˜๊ณ , ๊ทธ ์Šค๋ ˆ๋“œ๋“ค์ด ์žฌ์‚ฌ์šฉ๋˜๋ฉฐ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ๋” ๋งŽ์€ ์ž‘์—…์ด ๋“ค์–ด์˜ค๋ฉด ๋‚ด๋ถ€ ํ์— ์Œ“์ด๊ณ , ๊ธฐ์กด ์Šค๋ ˆ๋“œ๋“ค์ด ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•˜๋ฉด ์ˆœ์ฐจ์ ์œผ๋กœ ์†Œ๋น„๋ฉ๋‹ˆ๋‹ค. ExecutorService executor = Executors.newFixedThreadPool(4);ย  โœ… ์‚ฌ์šฉ ์‹œ์  * ์ฒ˜๋ฆฌํ•  ์ž‘์—…๋Ÿ‰์€ ๋งŽ์ง€๋งŒ, ๋™์‹œ์— ์ฒ˜๋ฆฌํ•ด์•ผ ํ•˜๋Š” ์ž‘์—… ์ˆ˜๋ฅผ ์ œํ•œํ•˜๊ณ  ์‹ถ์€ ๊ฒฝ์šฐ * CPU ์ž์›์„ ๊ณ ๋ฅด๊ฒŒ ์‚ฌ์šฉํ•˜๋ฉฐ, ์•ˆ์ •์ ์ธ ์ฒ˜๋ฆฌ๋Ÿ‰์„ ์›ํ•˜๋Š” ๊ฒฝ์šฐ ๐Ÿงช ์˜ˆ์‹œ for (int i = 0; i { System.out.println("Task " + taskId + " executed by " + Thread.currentThread().getName()); Thread.sleep(1000); // ๋ชจ์˜ ์ž‘์—… }); } โš ๏ธ ์ฃผ์˜ * ๊ณผ๋„ํ•˜๊ฒŒ ํฐ ์ž‘์—… ํ๊ฐ€ ์Œ“์ผ ์ˆ˜ ์žˆ์Œ โ†’ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰ ์ฆ๊ฐ€ * ์Šค๋ ˆ๋“œ ์ˆ˜๋Š” CPU ์ฝ”์–ด ์ˆ˜๋‚˜ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ํŠน์„ฑ์— ๋งž๊ฒŒ ์„ค์ •ํ•ด์•ผ ํ•จ ย  newCachedThreadPool() ์ด ์Šค๋ ˆ๋“œ ํ’€์€ ์š”์ฒญ์ด ๋งŽ์œผ๋ฉด ์ƒˆ๋กœ์šด ์Šค๋ ˆ๋“œ๋ฅผ ๊ณ„์† ์ƒ์„ฑํ•˜๊ณ , ํŠน์ • ๊ธฐ๊ฐ„ย ๋™์•ˆ ์‚ฌ์šฉ๋˜์ง€ ์•Š์œผ๋ฉด ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค. ์บ์‹œ๋œ ์Šค๋ ˆ๋“œ๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๋ฏ€๋กœ ๋น ๋ฅด๊ณ  ์œ ์—ฐํ•ฉ๋‹ˆ๋‹ค. ExecutorService executor = Executors.newCachedThreadPool(); โœ… ์‚ฌ์šฉ ์‹œ์  * ์ž‘์—…์ด ์งง๊ณ  ๋น ๋ฅด๊ฒŒ ๋๋‚˜๋Š” I/O ์ค‘์‹ฌ์˜ ์ž‘์—…์ผ ๋•Œ * ์งง์€ burst๊ฐ€ ์ž์ฃผ ๋ฐœ์ƒํ•˜๋Š” ์ƒํ™ฉ์—์„œ ์œ ์šฉ ๐Ÿงช ์˜ˆ์‹œ for (int i = 0; i { System.out.println("Task " + taskId + " executed by " + Thread.currentThread().getName()); }); }ย  โš ๏ธ ์ฃผ์˜ * ์š”์ฒญ์ด ๋งŽ์„ ๊ฒฝ์šฐ ์Šค๋ ˆ๋“œ๊ฐ€ ๋ฌด์ œํ•œ์œผ๋กœ ๋Š˜์–ด๋‚˜ ๊ณผ๋ถ€ํ•˜๊ฐ€ ๋  ์ˆ˜ ์žˆ์Œ โ†’ ์‹ค์ œ ์šด์˜์—์„œ๋Š” ThreadPoolExecutor๋กœ ์ปค์Šคํ…€ ์ œ์–ด ํ•„์š” ย  newSingleThreadExecutor() ํ•ญ์ƒ ๋‹จ ํ•˜๋‚˜์˜ ์Šค๋ ˆ๋“œ๋งŒ ์‚ฌ์šฉํ•˜์—ฌ ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ์ž‘์—…์€ FIFO ์ˆœ์„œ๋กœ ์‹คํ–‰๋˜๋ฉฐ, ์ˆœ์„œ๊ฐ€ ์ค‘์š”ํ•œ ๋กœ์ง์— ์ ํ•ฉํ•ฉ๋‹ˆ๋‹ค. ExecutorService executor = Executors.newSingleThreadExecutor(); โœ… ์‚ฌ์šฉ ์‹œ์  * ์ž‘์—… ์ˆœ์„œ๊ฐ€ ์ค‘์š”ํ•  ๋•Œ * ํ•˜๋‚˜์˜ ๋ฆฌ์†Œ์Šค(DB, ํŒŒ์ผ ๋“ฑ)์— ๋Œ€ํ•ด ์ง๋ ฌํ™”๋œ ์ ‘๊ทผ์ด ํ•„์š”ํ•  ๋•Œ ๐Ÿงช ์˜ˆ์‹œ for (int i = 0; i { System.out.println("Processing task " + taskId); Thread.sleep(500); }); }ย  โš ๏ธ ์ฃผ์˜ * ํ•˜๋‚˜์˜ ์Šค๋ ˆ๋“œ์— ์˜์กดํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ฒ˜๋ฆฌ๋Ÿ‰์€ ๋‚ฎ์Œ * ์Šค๋ ˆ๋“œ๊ฐ€ ์ฃฝ์œผ๋ฉด ์ƒˆ๋กœ์šด ์Šค๋ ˆ๋“œ๋กœ ๋Œ€์ฒด๋˜๋ฏ€๋กœ ์ค‘๋‹จ๋˜์ง€๋Š” ์•Š์Œ ย  newScheduledThreadPoool(int corePoolSize) ์ง€์—ฐ ์‹คํ–‰(delay)์ด๋‚˜ ์ฃผ๊ธฐ์ ์ธ ์ž‘์—…(interval) ์‹คํ–‰์— ํŠนํ™”๋œ ์Šค๋ ˆ๋“œ ํ’€์ž…๋‹ˆ๋‹ค. ScheduledExecutorService๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉฐ, Java์˜ ํƒ€์ด๋จธ ์—ญํ• ๋„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2); โœ… ์‚ฌ์šฉ ์‹œ์  * ์ฃผ๊ธฐ์ ์ธ ๋ฐฑ์—… ์ž‘์—…, ๋ชจ๋‹ˆํ„ฐ๋ง, ์•Œ๋ฆผ ์ „์†ก ๋“ฑ * ํŠน์ • ์‹œ๊ฐ„ ํ›„ ์ž‘์—…์„ ์‹คํ–‰ํ•˜๊ณ  ์‹ถ์„ ๋•Œ ๐Ÿงช ์˜ˆ์‹œ scheduler.scheduleAtFixedRate(() -> { System.out.println("Heartbeat sent by " + Thread.currentThread().getName()); }, 1, 5, TimeUnit.SECONDS); // 1์ดˆ ํ›„ ์‹œ์ž‘, 5์ดˆ๋งˆ๋‹ค ๋ฐ˜๋ณต โš ๏ธ ์ฃผ์˜ * ์ž‘์—…์ด ๋„ˆ๋ฌด ์˜ค๋ž˜ ๊ฑธ๋ฆฌ๋ฉด ๋‹ค์Œ ์ฃผ๊ธฐ ์ž‘์—…์ด ์ง€์—ฐ๋  ์ˆ˜ ์žˆ์Œ โ†’ ์ฒ˜๋ฆฌ ์‹œ๊ฐ„์ด ์ผ์ •ํ•˜์ง€ ์•Š๋‹ค๋ฉด scheduleWithFixedDelay()๋ฅผ ๊ณ ๋ ค ย  ย  ๐Ÿง  ๋งˆ๋ฌด๋ฆฌ Java์—์„œ Executors ํŒฉํ† ๋ฆฌ ๋ฉ”์„œ๋“œ๋Š” ๋‹ค์–‘ํ•œ ํ˜•ํƒœ์˜ ์Šค๋ ˆ๋“œ ํ’€์„ ๊ฐ„๋‹จํžˆ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋„์™€์ค๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ, ์šด์˜ ํ™˜๊ฒฝ์—์„œ๋Š” ThreadPoolExecutor๋ฅผ ์ง์ ‘ ์ƒ์„ฑํ•˜์—ฌ ์ž‘์—… ํ, ์ตœ๋Œ€ ์Šค๋ ˆ๋“œ ์ˆ˜, ๊ฑฐ๋ถ€ ์ •์ฑ… ๋“ฑ์„ ์„ธ๋ฐ€ํ•˜๊ฒŒ ์กฐ์ ˆํ•˜๋Š” ๊ฒƒ์ด ๋”์šฑ ์•ˆ์ „ํ•˜๊ณ  ํ™•์žฅ์„ฑ ์žˆ๋Š” ์„ ํƒ์ž…๋‹ˆ๋‹ค.

์•Œ๋ฆผ

์•Œ๋ฆผ์ด ์—†์Šต๋‹ˆ๋‹ค