Skip to content

Latest commit

ย 

History

History
685 lines (478 loc) ยท 26.7 KB

File metadata and controls

685 lines (478 loc) ยท 26.7 KB

๋ชฉ์ฐจ



๋“ค์–ด๊ฐ€๋ฉฐ

์ด์ „ ๊ธ€์—์„œ Thread์— ๋Œ€ํ•œ ๊ธฐ๋ณธ ๊ฐœ๋…๊ณผ Thread In Java์— ๋Œ€ํ•ด์„œ ๋‹ค๋ค˜๋‹ค๋ฉด ์ด๋ฒˆ ๊ธ€์—์„  ThreadPool์— ๋Œ€ํ•œ ๊ธฐ๋ณธ ๊ฐœ๋…๊ณผ ์ž๋ฐ”์—์„  ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉ๋˜๋Š”์ง€ ๋‹ค๋ฃฌ๋‹ค.

์šฐ์„  ThreadPool์— ๋Œ€ํ•œ ๊ธฐ๋ณธ์ ์ธ ๊ฐœ๋…์— ๋Œ€ํ•ด์„œ ๋‹ค๋ฃจ๊ณ , Java์—์„œ ThreadPool์„ ๋‹ค๋ฃจ๊ธฐ ์œ„ํ•ด ๊ผญ ์•Œ์•„์•ผํ•˜๋Š” Executor์™€ ExecutorService์— ๋Œ€ํ•ด์„œ ์ •๋ฆฌํ•˜์˜€๋‹ค.


ThreadPool์ด ๋“ฑ์žฅํ•˜๊ฒŒ ๋œ ๋ฐฐ๊ฒฝ


ThreadPool์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด

โ—๏ธ ThreadPool์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด

๋งŽ์€ ํ”„๋กœ๊ทธ๋žจ์€ ์Šค๋ ˆ๋“œ๋ฅผ ์ด์šฉํ•˜์—ฌ ๋ณ‘๋ ฌ (ํ˜น์€ ๋ณ‘ํ–‰)์ฒ˜๋ฆฌ๋ฅผ ํ•œ๋‹ค.

๋ฌธ์ œ๋Š” ์ ์ฐจ ํ•„์š”ํ•œ ์Šค๋ ˆ๋“œ์˜ ๊ฐœ์ˆ˜๊ฐ€ ๋งŽ์•„์ง€๋ฉด์„œ, ์žฆ์€ ์Šค๋ ˆ๋“œ ์ƒ์„ฑ๊ณผ ์Šค์ผ€์ค„๋ง์œผ๋กœ ์ธํ•ด CPU์™€ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰์ด ์ฆ๊ฐ€ํ•œ๋‹ค.

๊ฐ ์Šค๋ ˆ๋“œ๋Š” ๋ฉ”๋ชจ๋ฆฌ(RAM)๊ณผ ๊ฐ™์€ ํŠน์ • ์ˆ˜์ค€์˜ ์ปดํ“จํ„ฐ ๋ฆฌ์†Œ์Šค๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋™์‹œ์— ๋„ˆ๋ฌด ๋งŽ์€ ์Šค๋ ˆ๋“œ๊ฐ€ ํ™œ์„ฑ๋œ๋‹ค๋ฉด ์ปดํ“จํ„ฐ์˜ ์†๋„๊ฐ€ ์ €ํ•˜๋œ๋‹ค.

๋˜ํ•œ ์Šค๋ ˆ๋“œ์˜ ์ƒ์„ฑ ๊ฐœ์ˆ˜๋ฅผ ์ œ์–ดํ•˜๊ธฐ ํž˜๋“ค๊ธฐ ๋•Œ๋ฌธ์— ์ž์นซํ•˜๋ฉด ์ปดํ“จํ„ฐ๊ฐ€ ๋ฉˆ์ถœ ์ˆ˜๋„ ์žˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด, ๋ฉ”๋ชจ๋ฆฌ(RAM)์ด ๋„ˆ๋ฌด ๋งŽ์ด ์†Œ๋ชจ๋˜์–ด OS๊ฐ€ RAM์„ Disk๋กœ ์Šค์™‘์•„์›ƒํ•˜๊ธฐ ์‹œ์ž‘ํ•˜๋ฉด ์†๋„๋Š” ํ˜„์ €ํžˆ ๋А๋ ค์ง„๋‹ค.

๋ฌผ๋ก  ์Šค๋ ˆ๋“œ ์ƒ์„ฑ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ํšŒ์ˆ˜๋„ ํ•ด์•ผํ•œ๋‹ค..


โ—๏ธ ์ž๋ฐ” ์Šค๋ ˆ๋“œ์˜ ๋ฌธ์ œ

์ž๋ฐ” ์Šค๋ ˆ๋“œ๋Š” ์ง์ ‘ ์šด์˜์ฒด์ œ ์Šค๋ ˆ๋“œ์— ์ ‘๊ทผํ•œ๋‹ค. ์ด๋•Œ ์Šค๋ ˆ๋“œ๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ํšŒ์ˆ˜ํ•˜๋Š” ๋น„์šฉ์€ ์ƒ๊ฐ๋ณด๋‹ค ํฌ๋ฉฐ, ๋”์šฑ์ด ์šด์˜์ฒด์ œ ์Šค๋ ˆ๋“œ์˜ ์ˆซ์ž๋Š” ์ œํ•œ๋˜์–ด์žˆ๋‹ค.

๋งŒ์•ฝ ์šด์˜์ฒด์ œ๊ฐ€ ์ œ๊ณตํ•˜๋Š” ์Šค๋ ˆ๋“œ ๊ฐœ์ˆ˜์ด์ƒ์˜ ์Šค๋ ˆ๋“œ๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด ์ž๋ฐ” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์˜ˆ์ƒ์น˜ ๋ชปํ•˜๊ฒŒ ํฌ๋ž˜์‹œ๋  ์ˆ˜ ์žˆ๋‹ค.


ThreadPool์„ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด


๐Ÿ‘ ThreadPool์„ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด

ThreadPool์˜ ํ•ต์‹ฌ์€ ์Šค๋ ˆ๋“œ ์žฌ์‚ฌ์šฉ์ด๋‹ค.

ThreadPool์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๊ธฐ์กด์˜ Thread ์ „๋žต์€ ํ•œ๋ฒˆ ์‚ฌ์šฉํ•˜๋ฉด ์ข…๋ฃŒ๋˜๊ณ  ๋‹ค์‹œ ๋งŒ๋“ค์–ด์• ํ–ˆ๋‹ค.

ํ•˜์ง€๋งŒ ThreadPool์€ ์ •ํ•ด์ง„ ์ˆซ์ž๋งŒํผ ๋งŒ๋“ค์–ด๋‘” ๊ธฐ์กด ์Šค๋ ˆ๋“œ๋ฅผ ์ข…๋ฃŒ์‹œํ‚ค์ง€์•Š๊ณ  ๊ณ„์†ํ•ด์„œ ์ž‘์—…์„ ๋งก๊ฒจ ์‹คํ–‰ํ•˜๊ฒŒ ๋œ๋‹ค.

์Šค๋ ˆ๋“œ๋ฅผ ๋ฏธ๋ฆฌ ๋งŒ๋“ค์–ด๋‘๊ณ  ์ž‘์—…์ด ๋“ค์–ด์˜ฌ๋ฉด ์Šค๋ ˆ๋“œ๋“ค์—๊ฒŒ ์ž‘์—…์„ ์ ์ ˆํžˆ ๋ถ„๋ฐฐํ•œ๋‹ค.


๐Ÿค” ๊ทธ๋ž˜์„œ ๋ญ๊ฐ€ ์ข‹๋‹ค๋Š”๊ฑด๋ฐ? - Thread Pool์˜ ์žฅ์ 

๊ฒฐ๋ก ์ ์œผ๋ก  ์ •ํ•ด์ง„ ์ˆซ์ž์˜ ๊ธฐ์กด ์Šค๋ ˆ๋“œ๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ฆฌ์†Œ์Šค ์‚ฌ์šฉ๋Ÿ‰์„ ์ ˆ์•ฝํ•˜๊ณ , ์ด ์ฒ˜๋ฆฌ๋Ÿ‰๋„ ๋” ๋†’์ผ ์ˆ˜ ์žˆ๋‹ค.

  1. ์Šค๋ ˆ๋“œ ํ’€์„ ์‚ฌ์šฉํ•˜๋ฉด ํ•œ ๋ฒˆ์— ํ™œ์„ฑ ์ƒํƒœ์ธ ์Šค๋ ˆ๋“œ ์ˆ˜๋ฅผ ์‰ฝ๊ฒŒ ์ œ์–ดํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ์Šค๋ ˆ๋“œ์˜ ์ƒ์„ฑ๊ณผ ํšŒ์ˆ˜๋กœ ์ธํ•œ ๋ถ€ํ•˜๋ฅผ ์ค„์ผ ์ˆ˜ ์žˆ๋‹ค.
  2. ํ•œ ๋ฒˆ์— ๋งŽ์€ ์š”์ฒญ์ด ๋“ค์–ด์˜ฌ ๋•Œ ๋น ๋ฅด๊ณ  ํšจ์œจ์ ์œผ๋กœ ๋™์‹œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

ThreadPool์˜ ๋ฌธ์ œ์ ๊ณผ ์‚ฌ์šฉ์‹œ ์ฃผ์˜ํ•  ์ 

โ—๏ธ ๊ทธ๋ ‡๋‹ค๊ณ  ์ข‹์€ ๊ฒƒ๋งŒ์€ ์•„๋‹ˆ๋‹ค - Thread Pool์˜ ๋‹จ์ 

  1. ๋ฉ”๋ชจ๋ฆฌ ๋‚ญ๋น„
    • ThreadPool์€ Thread๋ฅผ ๋ฏธ๋ฆฌ ๋งŒ๋“ค์–ด๋‘๊ณ  ์žฌ์‚ฌ์šฉํ•œ๋‹ค๋Š” ์ธก๋ฉด์—์„œ ๊ต‰์žฅํžˆ ์œ ์šฉํ•œ ์†”๋ฃจ์…˜์ด๋‹ค.
    • ํ•˜์ง€๋งŒ ๋ช‡ ๊ฐœ์˜ Thread๋ฅผ ๋ฏธ๋ฆฌ ๋งŒ๋“ค์–ด๋‘˜์ง€๊ฐ€ ์ค‘์š”ํ•˜๋‹ค. ๋งŒ์•ฝ ๋„ˆ๋ฌด ๋งŽ์€ ์Šค๋ ˆ๋“œ๋ฅผ ๋งŒ๋“ค์–ด๋‘”๋‹ค๋ฉด ๋ฉ”๋ชจ๋ฆฌ๋งŒ ์ฐจ์ง€ํ•˜๊ณ  ์•„๋ฌด๊ฒƒ๋„ ํ•˜์ง€ ์•Š๋Š” ์Šค๋ ˆ๋“œ๊ฐ€ ์กด์žฌํ•  ์ˆ˜๋„ ์žˆ๋‹ค.
  2. ๋†€๊ณ ๋จน๋Š” ์Šค๋ ˆ๋“œ ๋ฐœ์ƒ ๊ฐ€๋Šฅ์„ฑ
    • ๋ณ‘๋ ฌ์ ์œผ๋กœ ์ฒ˜๋ฆฌ์š”์ฒญ์„ ํ•œ๋‹ค๋ฉด ํ•œ ์Šค๋ ˆ๋“œ๋Š” ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๋А๋ผ ํ—ˆ๋•์ด๊ณ  ์žˆ๋Š”์™€์ค‘์— ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ๋Š” ๋†€๊ณ ์žˆ์„ ์ˆ˜ ์žˆ๋‹ค.
    • ์ด๋กœ์ธํ•ด ๋ฏธ๋ฆฌ ๋งŒ๋“ค์–ด๋‘” ์Šค๋ ˆ๋“œ๋ฅผ ์ž˜ ํ™œ์šฉํ•˜์ง€ ๋ชปํ•  ์ˆ˜๋„ ์žˆ๋Š” ๋ฌธ์ œ๊ฐ€ ์žˆ๋‹ค.
    • ๋ฌผ๋ก  ์ด๋Š” ์ž๋ฐ”์—์„œ๋Š” ForkJoinPool์„ ์ง€์›ํ•œ๋‹ค.
  3. ๋†€๊ณ ๋จน๊ฑฐ๋‚˜ I/O ํ˜น์€ ๋„คํŠธ์›Œํฌ ์—ฐ๊ฒฐ์„ ๊ธฐ๋‹ค๋ฆฌ๋Š” ์Šค๋ ˆ๋“œ ์‚ฌ์šฉ์‹œ ์ฃผ์˜ํ•ด์•ผํ•œ๋‹ค.
    • ์Šค๋ ˆ๋“œ๊ฐ€ ์ž ์„ ์ž๊ฑฐ๋‚˜ I/O ํ˜น์€ ๋„คํŠธ์›Œํฌ ์—ฐ๊ฒฐ์„ ๊ธฐ๋‹ค๋ฆฌ๋ฉด ํ•ด๋‹น Task๋ฅผ ์‹คํ–‰ํ•˜๋Š” ์Šค๋ ˆ๋“œ๋Š” Blocking๋  ํ™•๋ฅ ์ด ๋†’๋‹ค. ์ฆ‰, ์Šค๋ ˆ๋“œ๋ฅผ ํ• ๋‹น๋ฐ›์•˜์œผ๋ฉด์„œ ์•„๋ฌด ์ž‘์—…๋„ ํ•˜์ง€์•Š๊ณ ์žˆ๋Š” ๊ฒƒ์ด๋‹ค.
    • ๊ทธ๋Ÿฌ๋ฏ€๋กœ ๊ฐ€๋Šฅํ•œ Blocking (์ž๊ฑฐ๋‚˜ ์ด๋ฒคํŠธ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๋Š”)์„ ๋ฐœ์ƒ์‹œํ‚ค๋Š” Task๋Š” ์Šค๋ ˆ๋“œ ํ’€์„ ์ด์šฉํ•˜์ง€์•Š๋Š”๊ฒŒ ์ข‹๋‹ค. (๋ฌผ๋ก  ์ด๋Š” ์ง€ํ‚ค๊ธฐ์–ด๋ ต๋‹ค...)
  4. DeadLock
    • ThreadPool๋งŒ์˜ ๋ฌธ์ œ๋ผ๊ธฐ๋ณด๋‹ค๋Š” ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋”ฉ ํ™˜๊ฒฝ์—์„œ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ๋Œ€ํ‘œ์ ์ธ ๋ฌธ์ œ์ ์€ ๋ฐ๋“œ๋ฝ์ด๋‹ค. ThreadPool๋„ ๋ฐ๋“œ๋ฝ์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.
    • ThreadPool์— ๊ฒฝ์šฐ, ๋งŒ์•ฝ ํ•˜๋‚˜์˜ Task์˜ ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๋Š” ๋˜ ๋‹ค๋ฅธ Task๋ฅผ Queue์— ๋„ฃ์œผ๋ฉด ๋ฐ๋“œ๋ฝ์ด ๋ฐœ์ƒํ•  ํ™•๋ฅ ์ด ๋†’๋‹ค.
  5. ์Šค๋ ˆ๋“œ ์—†์–ด์ง ๋ฌธ์ œ
    • ThreadPool์— ๋ฏธ๋ฆฌ ์ƒ์„ฑ๋œ ์Šค๋ ˆ๋“œ๊ฐ€ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๊ณ ๋‚˜์„œ ๋‹ค์‹œ ๋Œ€๊ธฐ์ƒํƒœ๊ฐ€ ์•ˆ๋˜๊ณ  ์ œ๊ฑฐ๋  ์ˆ˜ ์žˆ๋‹ค. (์žฌ์‚ฌ์šฉ ๋ถˆ๊ฐ€)
    • ์˜ˆ๋ฅผ ๋“ค์–ด, ์Šค๋ ˆ๋“œ์— ํ• ๋‹น๋œ Task๊ฐ€ ์˜ˆ์™ธ๋ฅผ ๋˜์กŒ๋Š”๋ฐ ํ•ด๋‹น ์˜ˆ์™ธ๋ฅผ ์žก์ง€ ๋ชปํ•œ๋‹ค๋ฉด Thread ์ž์ฒด๊ฐ€ ์ข…๋ฃŒ๋˜๊ธฐ ๋•Œ๋ฌธ์— ThreadPool์—์„œ ์Šค๋ ˆ๋“œ์˜ ๊ฐœ์ˆ˜๊ฐ€ ํ•˜๋‚˜์”ฉ ์ค„์–ด๋“ค ์ˆ˜ ์žˆ๋‹ค.

ThreadPool์€ ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ•˜๋Š”๊ฐ€?


์ถœ์ฒ˜: https://www.logicbig.com/tutorials/core-java-tutorial/java-multi-threading/thread-pools.html

์‚ฌ์‹ค ์œ„ ๊ทธ๋ฆผ๋งŒ๋ด๋„ ThreadPool์ด ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ•˜๋Š”์ง€ ์•Œ ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋ž˜๋„ ์กฐ๊ธˆ ๊ธ€๋กœ ์ •๋ฆฌํ•˜์ž๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  • ThreadPool์— ์š”๊ตฌ์— ๋งž๋Š” ์Šค๋ ˆ๋“œ๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด ๋ฏธ๋ฆฌ ์ƒ์„ฑํ•ด๋‘”๋‹ค. (New ThreadPool)
  • ์ƒˆ๋กœ์šด ์ž‘์—…์ด ๋“ค์–ด์˜ฌ ๋•Œ๋งˆ๋‹ค TaskQueue์— ๋„ฃ๋Š”๋‹ค. (New Task)
  • TaskQueue์—์„œ ํ•˜๋‚˜์”ฉ ๊บผ๋‚ด์„œ ๋ถ„ํ•  ๋ฐฉ์‹์—๋”ฐ๋ผ ์œ ํœด ์Šค๋ ˆ๋“œ์— ์ž‘์—…์„ ํ• ๋‹นํ•œ๋‹ค. (Thread Assignment)
  • ๊ฐ ์ž‘์—…์ด ์™„๋ฃŒ๋˜๋ฉด, ์ฝœ๋ฐฑ ํ˜•ํƒœ๋กœ ์ž‘์—…์„ ์š”์ฒญํ•œ ์ฃผ์ฒด์—๊ฒŒ ๊ฒฐ๊ณผ๋ฅผ ์•Œ๋ ค์ค€๋‹ค. (Task Finished)

ThreadPool์€ ์–ด๋ ต๊ณ  ๋ณต์žกํ•œ ๊ธฐ์ˆ ์ด๋ผ๊ธฐ๋ณด๋‹ค๋Š” ๊ทธ์ € Thread๋ฅผ ์ž˜ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒํ•ด์ฃผ๋Š” ๋””์ž์ธํŒจํ„ด์— ๊ฐ€๊น๋‹ค๊ณ  ์ƒ๊ฐํ•œ๋‹ค.


Thread Pool In Java

์ด์ œ ์ž๋ฐ”์—์„œ๋Š” ์–ด๋–ป๊ฒŒ Thread Pool์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ์‚ดํŽด๋ณธ๋‹ค.

์ž๋ฐ”๋Š” 5๋ฒ„์ „๋ถ€ํ„ฐ ์ž์ฒด์ ์œผ๋กœ Thread Pool์„ ์ง€์›ํ•˜๊ธฐ ์‹œ์ž‘ํ–ˆ๋‹ค. java.util.concurrent ํŒจํ‚ค์ง€์— ThreadPool๊ณผ ๊ด€๋ จ๋œ ํด๋ž˜์Šค๊ฐ€ ์กด์žฌํ•œ๋‹ค.

์ž๋ฐ”์—์„œ์˜ ThreadPool๋„ ์•„๋ž˜์™€ ๊ฐ™์ด ๋™์ผํ•˜๊ฒŒ ๋™์ž‘ํ•œ๋‹ค.


์ถœ์ฒ˜: https://www.baeldung.com/thread-pool-java-and-guava

์Šค๋ ˆ๋“œ ํ’€์˜ ์‹ค์ œ ๊ตฌํ˜„์—์„œ ์ฝ”๋“œ๋ฅผ ๋ถ„๋ฆฌํ•œ ์ƒํƒœ๋กœ ์œ ์ง€ํ•˜๊ณ  ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ „์ฒด์—์„œ ์ด๋Ÿฌํ•œ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ž๋ฐ”๋Š” ThreadPool๊ณผ ๊ด€๋ จ๋œ ์ฝ”๋“œ๋ฅผ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง๊ณผ ๋ถ„๋ฆฌ์‹œํ‚ค๊ธฐ์œ„ํ•ด Executor๊ณผ ExecutorService๋ผ๋Š” ์ธํ„ฐํŽ˜์ด์Šค๋กœ ์ถ”์ƒํ™”์‹œ์ผฐ์œผ๋ฉฐ, Executors๋ผ๋Š” ์œ ํ‹ธ์„ฑ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค์–ด ํŽธ์˜ ๋ฉ”์„œ๋“œ๋ฅผ ์ œ๊ณตํ•œ๋‹ค.


์Šค๋ ˆ๋“œ ํ’€ ์ถ”์ƒํ™” - Executor์™€ ExecutorService

์ž๋ฐ”๋Š” ์†์‰ฝ๊ฒŒ ์Šค๋ ˆ๋“œ ํ’€์„ ์ œ์–ดํ•  ์ˆ˜ ์žˆ๋„๋ก Executor์™€ ExecutorService๋ผ๋Š” ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ œ๊ณตํ•œ๋‹ค.

์‹ค์ œ๋กœ ์•„๋ž˜์™€ ๊ฐ™์ด ์†์‰ฝ๊ฒŒ ์Šค๋ ˆ๋“œ ํ’€์„ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

ThreadPool ์ƒ์„ฑ ์˜ˆ์‹œ (์Šค๋ ˆ๋“œ 100๊ฐœ)

ExecutorService threadPool = Executors.newFixedThreadPool(100);

์ƒ์„ฑํ•œ ์Šค๋ ˆ๋“œ ํ’€์— Task (Runnable ํ˜น์€ Callable)์„ ์ œ๊ณตํ•˜๋ฉด ์†์‰ฝ๊ฒŒ ์Šค๋ ˆ๋“œ ํ’€์•ˆ์˜ ์Šค๋ ˆ๋“œ๋กœ ์ด๋ฅผ ์‹คํ–‰์‹œํ‚ฌ ์ˆ˜ ์žˆ๊ฒŒ๋œ๋‹ค.


Executor vs ExecutorService

์ž๋ฐ”์—์„œ๋Š” ThreadPool๊ณผ ๊ด€๋ จ๋œ ์ฝ”๋“œ๋ฅผ Executor๊ณผ ExecutorService๋กœ ์ถ”์ƒํ™”์‹œ์ผฐ๋‹ค. ๊ทธ๋ ‡๋‹ค๋ฉด ์ด ๋‘˜์˜ ์ฐจ์ด์ ์€ ๋ฌด์—‡์ผ๊นŒ?


๐Ÿค” Executor

public interface Executor {
    // Executes the given command at some time in the future. 
    // The command may execute in a new thread, in a pooled thread, or in the calling thread, at the discretion of the Executor implementation.
    void execute(Runnable command);
}

Executor๋Š” ๋„˜๊ฒจ๋ฐ›์€ Runnable Task๋ฅผ ์‹คํ–‰ํ•˜๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ๊ฐ€์ง„ ๊ฐ„๋‹จํ•œ ์ธํ„ฐํŽ˜์ด์Šค๋‹ค.

์ธํ„ฐํŽ˜์ด์Šค๋กœ ๋”ฐ๋กœ ๋นผ๋‘” ์ด์œ ๋Š” ๋„˜๊ฒจ๋ฐ›์€ Task๋ฅผ ์Šค๋ ˆ๋“œ๊ฐ€ ์–ด๋–ป๊ฒŒ ์‹คํ–‰ํ• ์ง€, ์Šค๋ ˆ๋“œ ์Šค์ผ€์ค„๋ง์€ ์–ด๋–ป๊ฒŒ ํ• ์ง€๋“ฑ์„ ์ถ”์ƒํ™”์‹œํ‚ค๊ธฐ ์œ„ํ•จ์ด๋‹ค.

์‰ฝ๊ฒŒ ์–˜๊ธฐํ•˜์ž๋ฉด ๊ธฐ์กด์—” new Thread(new RunnableTask()).start()ํ•ด์•ผํ–ˆ๋˜ ์ž‘์—…์„ ์•„๋ž˜์™€ ๊ฐ™์ด ์ถ”์ƒํ™” ์‹œํ‚จ๊ฒƒ์ด๋‹ค.

Executor executor = anExecutor;
executor.execute(new RunnableTask1()); // ์ƒˆ๋กœ์šด Task๋ฅผ ์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌํ• ์ง€๋Š” Executor ๊ตฌํ˜„์ฒด์— ๋”ฐ๋ผ ๋‹ค๋ฅด๋‹ค.
executor.execute(new RunnableTask2());

์ž๋ฐ”๋Š” ์Šค๋ ˆ๋“œ๋ฅผ ์ง์ ‘ ๊ตฌํ˜„ํ•˜์—ฌ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ์ง€์›ํ•œ๋‹ค.

ํ•˜์ง€๋งŒ.. ์Šค๋ ˆ๋“œ๋ฅผ ์ง์ ‘ ๊ตฌํ˜„ํ•˜์—ฌ ์‚ฌ์šฉํ•˜๋ฉด, ์ฝ”๋“œ ๊ฐ€๋…์„ฑ์ด ๋„ˆ๋ฌด ๋–จ์–ด์ง€๋ฉฐ, ์ฝ”๋“œ๋งŒ ๋ณด๊ณ ๋Š” ์ •ํ™•ํžˆ ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ•˜๋Š”์ง€ ์•Œ๊ธฐ ์‰ฝ์ง€์•Š๋‹ค.

๊ทธ๋ฆฌํ•˜์—ฌ Thread Pool์˜ ๊ฐœ๋…๊ณผ ๊ฐ™์ด ์ž๋ฐ”๋Š” Thread๋ฅผ ๊ด€๋ฆฌํ•˜๊ณ  ๋ถ€๊ฐ€ ๋กœ์ง๊ณผ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์ธ ํ•ต์‹ฌ ๋กœ์ง์„ ๋ถ„๋ฆฌ์‹œํ‚ค๊ธฐ์œ„ํ•ด ๊ณ ์ˆ˜์ค€์˜ ์ธํ„ฐํŽ˜์ด์Šค์ธ Executor, ExecutorService, Executors๋“ฑ์„ ๋งŒ๋“ค์—ˆ๋‹ค.

์ฆ‰, Thread๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๊ด€๋ฆฌํ•˜๋Š” ๋ถ€๊ฐ€๋กœ์ง์„ ํ•ต์‹ฌ ๋กœ์ง์œผ๋กœ๋ถ€ํ„ฐ ๋ถ„๋ฆฌ์‹œํ‚จ ๊ฒƒ์ด๋‹ค.


์ด๋ ‡๊ฒŒ ์ถ”์ƒํ™”์‹œํ‚ด์œผ๋กœ์จ ์•„๋ž˜์™€๊ฐ™์ด ์ƒํ™ฉ์— ๋งž๊ฒŒ Executor ๊ตฌํ˜„์ฒด๋ฅผ ๋งŒ๋“ค์–ด Task๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ๋‹ค.


  1. ๋™๊ธฐ์ ์œผ๋กœ Task ์ฒ˜๋ฆฌ (Thread๋ฅผ ํ™œ์šฉํ•œ ๋น„๋™๊ธฐ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์Œ)
class DirectExecutor implements Executor {
    public void execute(Runnable r) {
        r.run();
    }
}

  1. ๋งค Task๋งˆ๋‹ค ์ƒˆ๋กœ์šด ์Šค๋ ˆ๋“œ๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ์ฒ˜๋ฆฌ
class ThreadPerTaskExecutor implements Executor {
    public void execute(Runnable r) {
        new Thread(r).start();
    }
}

  1. Task๋ฅผ ํŠน์ • ์Šค๋ ˆ๋“œ์— ์Šค์ผ€์ค„๋งํ•  ๋•Œ ์ปดํฌ์ง€ํŠธ ํ˜น์€ ํ”„๋ก์‹œ ํŒจํ„ด๊ณผ ๊ฐ™์ด ์‚ฌ์šฉํ•˜์—ฌ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.
class SerialExecutor implements Executor {
    final Queue<Runnable> tasks = new ArrayDeque<Runnable>();
    final Executor executor;
    Runnable active;

    SerialExecutor(Executor executor) {
        this.executor = executor;
    }

    public synchronized void execute(final Runnable r) {
        tasks.offer(new Runnable() {
           try {
              r.run();
           } final {
              // ๋งค Task๋งˆ๋‹ค ๋๋‚˜๋ฉด ๋‹ค์Œ Task ํ˜ธ์ถœ.
              scheduleNext();
           }
        });

        // ๋งŒ์•ฝ ํ˜„์žฌ active(์‹คํ–‰)๋˜๊ณ ์žˆ๋Š” Task๊ฐ€ ์—†๋‹ค๋ฉด ๋‹ค์Œ Task ํ˜ธ์ถœ.
        if (active == null) {
           scheduleNext();
        }
    }

    // TaskQueue์—์„œ ๋‹ค์Œ Task๋ฅผ ๊บผ๋‚ด์„œ ์Šค๋ ˆ๋“œ์— ์Šค์ผ€์ค„๋ง. (์‹คํ–‰)
    protected synchronized void scheduleNext() {
        if ((active == tasks.poll() != null)) {
            executor.execute(active);
        }
    }
}

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


๐Ÿค” ExecutorService

public interface ExecutorService extends Executor {

    void shutdown();

    List<Runnable> shutdownNow();

    boolean isShutdown();

    boolean isTerminated();

    boolean awaitTermination(long timeout, TimeUnit unit)
        throws InterruptedException;

    <T> Future<T> submit(Callable<T> task);

    <T> Future<T> submit(Runnable task, T result);

    Future<?> submit(Runnable task);

    <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
        throws InterruptedException;

    <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
                                  long timeout, TimeUnit unit)
        throws InterruptedException;

    <T> T invokeAny(Collection<? extends Callable<T>> tasks)
        throws InterruptedException, ExecutionException;

    <T> T invokeAny(Collection<? extends Callable<T>> tasks,
                    long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}

ExecutorService๋Š” Task๋ฅผ ๊ด€๋ฆฌํ•˜๊ณ  ์ œ์–ดํ•˜๋Š”๋ฐ ์‚ฌ์šฉ๋˜๋Š” Execute ์ธํ„ฐํŽ˜์ด์Šค์˜ ํ•˜์œ„ ์ธํ„ฐํŽ˜์ด์Šค์ด๋‹ค.

์‰ฝ๊ฒŒ ๋งํ•ด Execute๋ณด๋‹ค ๋” ํ™•์žฅ๋œ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๊ธฐ์œ„ํ•œ ์ธํ„ฐํŽ˜์ด์Šค์ด๋‹ค.

ThreadPool์„ ์ข…๋ฃŒํ•˜๋Š” ๋ฉ”์„œ๋“œ์™€ ํ•˜๋‚˜ ์ด์ƒ์˜ ๋น„๋™๊ธฐ ์ž‘์—…์„ ์ถ”์ ํ•˜๊ธฐ ์œ„ํ•œ Future๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ์ œ๊ณตํ•œ๋‹ค.

  • ExecutorService๋Š” ์•ˆ์ „ํ•˜๊ฒŒ ์ข…๋ฃŒํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋‘ ๋ฉ”์„œ๋“œ๋ฅผ ์ œ๊ณตํ•œ๋‹ค.
    • shutdown(): ์ข…๋ฃŒ์ „์— ์š”์ฒญ๋œ Task (์‹คํ–‰์ค‘์ธ Task + ๋Œ€๊ธฐ์ค‘์ธ Task)๋Š” ๋ชจ๋‘ ์ˆ˜ํ–‰ํ•˜๋„๋กํ•˜๊ณ  ์ข…๋ฃŒ๋œ๋‹ค.
    • shutdownNow(): ๋Œ€๊ธฐ ์ค‘์ธ Task๊ฐ€ ์‹œ์ž‘๋˜๋Š” ๊ฒƒ์„ ๋ฉˆ์ถ”๋„๋กํ•˜๊ณ , ํ˜„์žฌ ์‹คํ–‰์ค‘์ธ Task๋„ ์ค‘์ง€ํ•œ๋‹ค.
  • ExecutorService๋Š” Executor.execute(Runnable)๋ฅผ ํ™•์žฅํ•˜์—ฌ Task๋ฅผ ์ทจ์†Œํ•˜๊ฑฐ๋‚˜ ์™„๋ฃŒ๋ฅผ ๊ธฐ๋‹ค๋ฆด ๋•Œ ์‚ฌ์šฉ๋˜๋Š” Future์„ ๋งŒ๋“ค์–ด ๋ฐ˜ํ™˜ํ•œ๋‹ค.
  • ExecutorService๋Š” invokeAny์™€ invokeAll์„ ํ†ตํ•ด ์—ฌ๋Ÿฌ ๊ฐœ์˜ Task๋ฅผ ํ•œ๋ฒˆ์— Submit๋˜๋„๋ก ๋ฒŒํฌ ์—ฐ์‚ฐ์„ ์ง€์›ํ•œ๋‹ค.

๐Ÿค” Executor vs ExecutorService

  • Executor: ์ฃผ์–ด์ง„ Runnable์„ ์‹คํ–‰๋งŒ ํ•œ๋‹ค.
  • ExecutorService: Execute์˜ ํ™•์žฅ -> Execute์˜ ์‹คํ–‰๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์‹œ์ž‘ํ•˜๊ฑฐ๋‚˜ ์ข…๋ฃŒํ•˜๋Š”๋“ฑ์˜ ์—ฌ๋Ÿฌ ๊ธฐ๋Šฅ์„ ํ™•์žฅ.

๐Ÿ’โ€โ™‚๏ธ ๊ฐ„๋‹จ ์˜ˆ์‹œ - Thread Pool์„ ํ™œ์šฉํ•˜์—ฌ ๋“ค์–ด์˜ค๋Š” ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ์˜ˆ์‹œ

NetworkService.java

class NetworkService implements Runnable {
    private final ServerSocket serverSocket;
    private final ExecutorService pool;

    public NetworkService(int port, int poolSize) throws IOException {
        serverSocket = new ServerSocket(port);
        pool = Executors.newFixedThreadPool(poolSize);
    }

    public void run {
        try {
           for (;;) {
              pool.execute(new Handler(serverSocket.accept()));
           }
        } catch (IOException ex) {
           pool.shutdown();
        }
    }
}

Handler.java

class Handler implements Runnable {
    private final Socket socket;
    
    Handler (Socket socket) {
        this.socket = socket;
    }

    public void run() {
       // read and service request on socket
    }
}

ThreadPool ์‚ฌ์šฉ ์˜ˆ์‹œ

์ž๋ฐ”์—์„œ ์ œ๊ณตํ•˜๋Š” FixedThreadPool์„ ์ด์šฉํ•œ ๊ฐ„๋‹จํ•œ ์Šค๋ ˆ๋“œ ํ’€ ์˜ˆ์‹œ


Task.java

public class Task implements Runnable {

    private String name;

    public Task(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        try {
            for (int i = 0; i < 5; i++) {
                Date now = new Date();
                SimpleDateFormat dateFormat = new SimpleDateFormat("hh:mm:ss");

                if (i == 0) {
                    System.out.println(this.name + "  ์‹œ์ž‘ - " + dateFormat.format(now));
                } else {
                    System.out.println(this.name + " ์‹คํ–‰ - " + dateFormat.format(now));
                }
                Thread.sleep(1_000);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(this.name + " Task ์™„๋ฃŒ");
    }
}

ExampleMain.java

public class ExampleMain {

    public static void main(String[] args) {
        // given
        Runnable task1 = new Task("Task 1");
        Runnable task2 = new Task("Task 2");
        Runnable task3 = new Task("Task 3");
        Runnable task4 = new Task("Task 4");
        Runnable task5 = new Task("Task 5");

        ExecutorService threadPool = Executors.newFixedThreadPool(3); // ThreadPool์˜ Queue ์ตœ๋Œ€ ์‚ฌ์ด์ฆˆ 3๊ฐœ ์„ค์ •

        // when
        threadPool.execute(task1);
        threadPool.execute(task2);
        threadPool.execute(task3);
        threadPool.execute(task4);
        threadPool.execute(task5);

        // and
        threadPool.shutdown();
    }
}


์‹คํ–‰ ๊ฒฐ๊ณผ

  • ThreadPool์˜ ThreadCore ์ตœ๋Œ€ ์‚ฌ์ด์ฆˆ๋ฅผ 3๊ฐœ๋กœ ์„ค์ •ํ•˜์—ฌ 5๊ฐœ์˜ Task๋ฅผ ์š”์ฒญํ•œ ์˜ˆ์‹œ์ด๋‹ค.
    • ์ตœ๋Œ€ ์‚ฌ์ด์ฆˆ๊ฐ€ 3์ด๊ธฐ ๋•Œ๋ฌธ์— Task4์™€ Task5๋Š” Task1, 2, 3์ค‘ ํ•˜๋‚˜๊ฐ€ ๋๋‚˜ ์™„๋ฃŒ ์ƒํƒœ๊ฐ€๋˜์„œ์•ผ ์‹œ์ž‘ํ•˜๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

ExecutorService

์ž๋ฐ”์—์„œ ThreadPool์„ ์‚ฌ์šฉํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด ๋Œ€๋ถ€๋ถ„ ExecutorService๋ฅผ ๊ตฌํ˜„ํ•œ ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. ๊ฐ€์žฅ ์ค‘์š”ํ•˜๋‹ค๊ณ  ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

์‹ค์ œ๋กœ HikariCP์˜ ์ผ๋ถ€ ์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด ExecutorService๋ฅผ ๊ตฌํ˜„ํ•œ ThreadPoolExecutor๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

์ •ํ™•ํ•œ ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค.. ์ถ”ํ›„์— HikariCP๋ฅผ ์ •๋ฆฌํ•  ๋•Œ ํ•œ๋ฒˆ ๋” ์•Œ์•„๋ณผ ์˜ˆ์ •.

์ด๋ฒˆ ์ฑ•ํ„ฐ์—์„  ExecutorService์˜ ๋Œ€ํ•ด์„œ ์ •๋ฆฌํ•˜์˜€๋‹ค.

์šฐ์„  ์–ด๋–ป๊ฒŒ ์ƒ์„ฑํ•˜๋Š”์ง€, ์–ด๋–ค ๊ตฌํ˜„์ฒด๊ฐ€ ์žˆ๋Š”์ง€ ์„ค๋ช…ํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  Task๋ฅผ ์–ด๋–ค ๋ฐฉ์‹์œผ๋กœ ์š”์ฒญํ•˜๊ณ  ์ปจํŠธ๋กคํ•˜๋Š”์ง€์— ๋Œ€ํ•ด์„œ ๋‹ค๋ฃฌ๋‹ค.

ExecutorService๊ฐ€ ๋ฌด์—‡์ธ์ง€์— ๋Œ€ํ•ด์„  ์œ„์— ์ •๋ฆฌํ•œ ๋‚ด์šฉ์„ ์ฐธ๊ณ .


ExecutorService ๊ตฌํ˜„์ฒด

์ž๋ฐ”์—์„œ ์ œ๊ณตํ•˜๋Š” ExecutorService์˜ ๊ตฌํ˜„์ฒด๋Š” ๋‹ค์–‘ํ•˜๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ด ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•œ ๊ฐ์ฒด๋Š” ThreadPool ์—ญํ• ์„ ํ•œ๋‹ค.

๊ทธ๋Ÿฐ ์˜๋ฏธ์—์„œ ExecutorService๋ฅผ ๊ตฌํ˜„ํ•œ ๊ตฌํ˜„์ฒด ๋Œ€๋ถ€๋ถ„์€ ThreadPool์ด๋ผ๊ณ  ๋ด๋„ ๋  ๊ฒƒ ๊ฐ™๋‹ค.

ExecutorService์˜ ๊ตฌํ˜„์ฒด๋Š” ํฌ๊ฒŒ ๋‘ ๊ฐœ๋กœ ๋‚˜๋‰œ๋‹ค.

  • java.util.concurrent.ThreadPoolExecutor
  • java.util.concurrent.ScheduledExecutorService

๐Ÿ’โ€โ™‚๏ธ java.util.concurrent.ThreadPoolExecutor


// ์ง์ ‘ ์ƒ์„ฑ
int  corePoolSize  =    5;
int  maxPoolSize   =   10;
long keepAliveTime = 5000;

ExecutorService threadPoolExecutor =
        new ThreadPoolExecutor(
                corePoolSize,
                maxPoolSize,
                keepAliveTime,
                TimeUnit.MILLISECONDS,
                new LinkedBlockingQueue<Runnable>()
        );

// Executors ์ด์šฉํ•˜์—ฌ ์ƒ์„ฑ
ExecutorService executorService = Executors.newSingleThreadExecutor();
ExecutorService executorService = Executors.newFixedThreadPool(int nThreads);
ExecutorService executorService = Executors.newCachedThreadPool();
  • ๋™์ž‘ ๊ณผ์ •
    • ์ฃผ์–ด์ง„ Task (Callable ํ˜น์€ Runnable)์„ ๋‚ด๋ถ€์ ์œผ๋กœ ๋™์ž‘ํ•˜๊ณ  ์žˆ๋Š” ThreadPool์„ ์ด์šฉํ•ด์„œ ์‹คํ–‰ํ•œ๋‹ค.
  • ์„ค์ •
    • Thread ๊ฐœ์ˆ˜
      • corePoolSize: Thread ๊ฐœ์ˆ˜ (Thread๊ฐ€ ๋†€๊ณ ์žˆ์–ด๋„ ๊ณ„์† ์œ ์ง€๋˜๋Š” ๊ฐœ์ˆ˜)
      • maximumPoolSize: ์ตœ๋Œ€ Thread ๊ฐœ์ˆ˜ (TaskQueue๊ฐ€ Full์ธ ์ƒํƒœ์—์„œ corePoolSize๋ณด๋‹ค ๋” ๋งŽ์€ ์Šค๋ ˆ๋“œ๊ฐ€ ํ•„์š”ํ•˜๋ฉด Thread๋ฅผ ์ƒ์„ฑํ•œ๋‹ค. ์ด๋•Œ์˜ ์ตœ๋Œ€ ์ƒ์„ฑ ๊ฐœ์ˆ˜)
    • KeepAliveTime: Thread KeepAlive ์‹œ๊ฐ„
    • unit: KeepAliveTime ๋‹จ์œ„
    • workQueue: TaskQueue์˜ ๊ตฌํ˜„์ฒด (ex. Runnable์„ ์ €์žฅํ•˜๋Š” BlockingQueue)
  • Executors์—์„œ ์ œ๊ณตํ•˜๋Š” ํŽธ์˜ ๋ฉ”์„œ๋“œ
    • Executors.newSingleThreadExecutor(): ๋‹จ์ผ ์Šค๋ ˆ๋“œ ์ƒ์„ฑ
      • ์‹คํŒจ ์‹œ ์ƒˆ๋กœ ์Šค๋ ˆ๋“œ๋ฅผ ์ƒ์„ฑํ•˜์ง€ ์•Š๋Š”๋‹ค -> corePoolSize: 1, maximumPoolSize: 1
    • Executors.newFixedThreadPool(int nThreads): ๊ณ ์ • ๊ฐœ์ˆ˜์˜ ์Šค๋ ˆ๋“œ ์ƒ์„ฑ.
      • ๋ชจ๋“  ์Šค๋ ˆ๋“œ๊ฐ€ ์ž‘์—…์ค‘์ด๋ฉด TaskQueue์— ์ž‘์—…์„ ์ ์žฌํ•œ๋‹ค. -> corePoolSize: n, maximumPoolSize: n
    • Executors.newCachedThreadPool(): ํ•„์š”์— ๋”ฐ๋ผ ์ƒˆ๋กœ์šด ์Šค๋ ˆ๋“œ๋ฅผ ์ƒ์„ฑํ•˜๋ฉฐ, ์ด์ „์— ์ƒ์„ฑํ–ˆ๋˜ ์Šค๋ ˆ๋“œ๊ฐ€ ์กด์žฌํ•˜๋ฉด ์žฌ์‚ฌ์šฉํ•œ๋‹ค.
      • ๋””ํดํŠธ๋กœ๋Š” 60์ดˆ๋™์•ˆ ์Šค๋ ˆ๋“œ๊ฐ€ ์œ ์ง€๋œ๋‹ค. -> corePoolSize: 0, maximumPoolSize: Integer.MAX_VALUE

์„ค์ •์— ๋Œ€ํ•œ ๋” ์ž์„ธํ•œ ๋‚ด์šฉ์€ ์—ฌ๊ธฐ๋ฅผ ์ฐธ๊ณ .


๐Ÿ’โ€โ™‚๏ธ java.util.concurrent.ScheduledThreadPoolExecutor


public class ScheduledExecutorExample {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ScheduledExecutorService scheduledExecutorService =
                Executors.newScheduledThreadPool(5);

        ScheduledFuture<String> scheduledFuture =
                scheduledExecutorService.schedule(
                        () -> {
                            System.out.println("Executed!");
                            return "Callable Result";
                        },
                        5,
                        TimeUnit.SECONDS
                );
        
        System.out.println("์‹คํ–‰ ๊ฒฐ๊ณผ (5์ดˆํ›„) : " + scheduledFuture.get());
        scheduledExecutorService.shutdown();
    }
}
// ๊ฒฐ๊ณผ
Executed!
์‹คํ–‰ ๊ฒฐ๊ณผ (5์ดˆํ›„) : Callable Result
  • ๋™์ž‘๊ณผ์ •
    • ์ง€์ •๋œ ์‹œ๊ฐ„๋งŒํผ Delayํ›„ Task๋ฅผ ์‹คํ–‰ํ•˜๊ฑฐ๋‚˜ ์ฃผ๊ธฐ์ ์œผ๋กœ ์‹คํ–‰ํ•œ๋‹ค.
    • ThreadPoolExecutor๊ณผ ๋™์ผํ•˜๋‹ค. ๋‹ค๋งŒ ScheduledExecutorService์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•จ์œผ๋กœ์จ schedule ๋ฉ”์„œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•˜๊ณ  ์žˆ๋‹ค.
      • public class ScheduledThreadPoolExecutor extends ThreadPoolExecutor implements ScheduledExecutorService {}
  • ์ฃผ์š” ๋ฉ”์„œ๋“œ
    • schedule(Callable task, long delay, TimeUnit timeunit)
    • schedule(Runnable task, long delay, TimeUnit timeunit)
    • scheduleAtFixedRate(Runnable task, long initialDelay, long period, TimeUnit timeunit)
    • scheduleWithFixedDelay(Runnable task, long initialDelay, long period, TimeUnit timeunit)

๋” ์ž์„ธํ•œ ๋‚ด์šฉ์€ ์—ฌ๊ธฐ๋ฅผ ํ™•์ธ.


๊ผญ Shutdown์„ ํ•ด์ค˜์•ผํ•œ๋‹ค

๋ชจ๋“  ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๊ณ  ๋” ์ด์ƒ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ์–ด๋– ํ•œ ExecutorService๋“  shutdown()์„ ํ•ด์•ผํ•œ๋‹ค.

์•ˆ๊ทธ๋Ÿผ JVM์ด ๊ณ„์†ํ•ด์„œ ThreadPool์˜ Thread๊ฐ€ ํ™œ์„ฑํ™”๋œ ์ƒํƒœ์—์„œ Task๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๊ธฐ ๋•Œ๋ฌธ์— ํ”„๋กœ๊ทธ๋žจ์ด ์ข…๋ฃŒ๋˜์ง€ ์•Š๋Š”๋‹ค.

์ข…๋ฃŒ์‹œํ‚ค๋Š” ๋ฉ”์„œ๋“œ๋กœ๋Š” shutdown(), shutdownNow(), awaitTermination()๋“ฑ์ด ์žˆ๋‹ค.


invokeAny() vs invokeAll()

invoke๊ฐ€ ๋ถ™์€ ๋ฉ”์„œ๋“œ๋Š” ์—ฌ๋Ÿฌ ๊ฐœ์˜ Task๋ฅผ ํ•œ๋ฒˆ์— ์š”์ฒญํ•  ๋•Œ ์‚ฌ์šฉ๋œ๋‹ค.


๐Ÿ’โ€โ™‚๏ธ invokeAny()

invokeAny()๋Š” Callable์„ ๊ตฌํ˜„ํ•œ ๊ฐ์ฒด(Task)์˜ ์ปฌ๋ ‰์…˜์„ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋ฐ›๋Š”๋‹ค.

๋งค Callable์˜ Future๋ฅผ ๋ฐ˜ํ™˜ํ•˜์ง€ ์•Š๊ณ , ๋„˜๊ฒจ๋ฐ›์€ ์ปฌ๋ ‰์…˜์ค‘ ํ•˜๋‚˜์˜ Callable์— ๋Œ€ํ•œ ๊ฒฐ๊ณผ๋งŒ์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

<T> T invokeAny(Collection<? extends Callable<T>> tasks) throws ...

์ฆ‰, ์š”์ฒญํ•œ Task (Callable)์ค‘์—์„œ ํ•˜๋‚˜๋ผ๋„ ์™„๋ฃŒ๋˜๋ฉด ํ•ด๋‹น Task์˜ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๊ณ , ๋‚˜๋จธ์ง€ Task๋Š” ๋ชจ๋‘ Cancelํ•œ๋‹ค.

If one of the tasks complete (or throws an exception), the rest of the Callable's are cancelled.


// invokeAny() ์˜ˆ์‹œ
public static void main(String[] args) throws ExecutionException, InterruptedException {
    ExecutorService executorService = Executors.newSingleThreadExecutor();

    Set<Callable<String>> callables = new HashSet<>();
    callables.add(() -> "Task 1 Completed");
    callables.add(() -> "Task 2 Completed");
    callables.add(() -> "Task 3 Completed");

    String result = executorService.invokeAny(callables);
    System.out.println(result); // Task 1 or Task 2 or Task 3

    executorService.shutdown();
}

// ๊ฒฐ๊ณผ
// Task 1 Completed ํ˜น์€ Task 2 Completed ํ˜น์€ Task 3 Completed

๐Ÿ’โ€โ™‚๏ธ invokeAll()

invokeAll() ๋ฉ”์„œ๋“œ๋Š” invokeAny()์™€ ๋‹ค๋ฅด๊ฒŒ ๋ชจ๋“  Task๊ฐ€ ์™„๋ฃŒ๋˜์–ด์•ผ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

ํ•˜๋‚˜๋ผ๋„ ์™„๋ฃŒ๋˜์ง€ ์•Š์•˜๋‹ค๋ฉด holding๋œ๋‹ค.

๊ฒฐ๊ณผ๋Š” List<Future>๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉฐ, ๋„˜๊ฒจ๋ฐ›์€ Task (Callable)๊ฐ€ ์ •์ƒ ์ฒ˜๋ฆฌ๋˜์—ˆ๋˜ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•˜์—ฌ ๋๋‚ฌ๋˜ ์™„๋ฃŒ๋œ ๊ฒƒ์œผ๋กœ ๋ณธ๋‹ค.

์ฆ‰, ๋™์ž‘์ค‘์— ์ „๋‹ฌ๋ฐ›์€ Task๋“ค์ด ๋ณ€๊ฒฝ๋˜๊ฑฐ๋‚˜ ์ž˜๋ชป๋˜์–ด๋„ ๊ฒฐ๊ณผ๋ฅผ ๋ณด์žฅํ•˜์ง€ ์•Š๋Š”๋‹ค.

์ž˜๋ชป์‚ฌ์šฉํ•˜๋ฉด ์š”์ฒญํ•œ Callable ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๋А๋ผ Blocking์ด ๋˜์–ด ์›์น˜์•Š๊ฒŒ ์„ฑ๋Šฅ์ด ์ €ํ•˜๋  ์ˆ˜๋„ ์žˆ๋‹ค.


// invokeAll() ์˜ˆ์‹œ
public static void main(String[] args) throws InterruptedException, ExecutionException {
    ExecutorService executorService = Executors.newSingleThreadExecutor();

    Set<Callable<String>> callables = new HashSet<>();
    callables.add(() -> "Task 1 Completed");
    callables.add(() -> "Task 2 Completed");
    callables.add(() -> "Task 3 Completed");

    // ๋งŒ์•ฝ Task๋“ค์˜ ์‹œ๊ฐ„์ด ์˜ค๋ž˜ ๊ฑธ๋ฆฐ๋‹ค๋ฉด ์—ฌ๊ธฐ์„œ Block๋˜์–ด ์„ฑ๋Šฅ์ด ์ €ํ•˜๋  ์ˆ˜๋„ ์žˆ๋‹ค.
    List<Future<String>> futures = executorService.invokeAll(callables);

    for (Future<String> future : futures) {
        System.out.println(future.get());
    }

    executorService.shutdown();
}
// ๊ฒฐ๊ณผ
Task 2 Completed
Task 3 Completed
Task 1 Completed

Task Cancel

ExecutorService์— ์š”์ฒญํ•œ Task (Runnable ํ˜น์€ Callable)์€ Future.cancel()๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์ทจ์†Œํ•  ์ˆ˜ ์žˆ๋‹ค.

๋‹ค๋งŒ, Task๊ฐ€ ์•„์ง ์‹คํ–‰์ „์ผ ๋•Œ๋งŒ ์ทจ์†Œํ•  ์ˆ˜ ์žˆ๋‹ค. ๋งŒ์•ฝ ์‹คํ–‰์ค‘์ด๋ผ๋ฉด ์ทจ์†Œํ•  ์ˆ˜ ์—†๋‹ค.

future.cancel();

๋งˆ์น˜๋ฉฐ

์˜ˆ์ƒ๋ณด๋‹ค ๊ธ€์ด ๊ธธ์–ด์กŒ๋‹ค. ๊ทธ๋ž˜๋„ ThreadPool์— ๋Œ€ํ•œ ๊ฐœ๋…์„ ์žก์„ ์ˆ˜ ์žˆ์—ˆ๊ณ , ์ž๋ฐ”์—์„  ์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌํ•˜๋Š”์ง€ ํฐ๊ทธ๋ฆผ์„ ๊ทธ๋ฆด ์ˆ˜ ์žˆ์—ˆ๋‹ค.

๋ˆ„๊ตฐ๊ฐ€์—๊ฒ ๋„์›€์ด ๋˜๋Š” ๊ธ€์ด ๋˜๊ธฐ๋ฅผ~~~

๊ฐ„๋‹จํ•œ ThreadPool์„ ์ง์ ‘ ๊ตฌํ˜„ํ•ด๋ณด๊ณ ์‹ถ๋‹ค๋ฉด ์—ฌ๊ธฐ๋ฅผ ์ฐธ๊ณ ํ•˜๋ฉด ๋œ๋‹ค.

ํ•„์ž๋Š” ์ง์ ‘ ๊ตฌํ˜„ํ•ด๋ณด๋‹ˆ ๋งŽ์€ ๋„์›€์ด ๋˜์—ˆ๋‹ค.

๋‹ค์Œ ๊ธ€๋ถ€ํ„ฐ ๋น„๋™๊ธฐ ์ฒ˜๋ฆฌ์— ๋Œ€ํ•ด์„œ ์ •๋ฆฌํ•œ๋‹ค. ์•„๋งˆ ๋‹ค์Œ ๊ธ€์€ Future์— ๋Œ€ํ•œ ๊ธ€์ผ ๋“ฏ ์‹ถ๋‹ค.


์ฐธ๊ณ