item 80 kyunghee - JAVA-JIKIMI/EFFECTIVE-JAVA3 GitHub Wiki

์Šค๋ ˆ๋“œ๋ณด๋‹ค๋Š” ์‹คํ–‰์ž, ํƒœ์Šคํฌ, ์ŠคํŠธ๋ฆผ์„ ์• ์šฉํ•˜๋ผ

๋‹จ์ˆœํ•œ ์ž‘์—… ํ(work queue)

  • ์ด ํด๋ž˜์Šค์—์„œ๋Š” ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์š”์ฒญํ•œ ์ž‘์—…์„ ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์Šค๋ ˆ๋“œ์— ์œ„์ž„ํ•ด ๋น„๋™๊ธฐ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•ด์คฌ๋‹ค.
  • ์ž‘์—… ํ๊ฐ€ ํ•„์š” ์—†์–ด์ง€๋ฉด ํด๋ผ์ด์–ธํŠธ๋Š” ํ์— ์ค‘๋‹จ์„ ์š”์ฒญํ•  ์ˆ˜ ์žˆ๊ณ  ๊ทธ๋Ÿฌ๋ฉด ํ๋Š” ๋‚จ์•„ ์žˆ๋Š” ์ž‘์—…์„ ๋งˆ์ € ์™„๋ฃŒํ•œ ํ›„ ์Šค์Šค๋กœ ์ข…๋ฃŒํ•œ๋‹ค.

๋™์‹œ์„ฑ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์ธก๋ฉด์—์„œ ์ž๋ฐ”๋Š” ์•ž์„œ ๋‚˜์•„๊ฐ

  • ์ฒ˜์Œ ๋ฆด๋ฆฌ์ฆˆ๋œ 1996๋…„ ๋ถ€ํ„ฐ ์Šค๋ ˆ๋“œ, ๋™๊ธฐํ™”, wait/notify๋ฅผ ์ง€์›
  • ์ž๋ฐ” 5๋ถ€ํ„ฐ๋Š” ๋™์‹œ์„ฑ ์ปฌ๋ ‰์…˜์ธ java.util.concurrent ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์™€ Excutor Framework๋ฅผ ์ง€์›
  • ์ž๋ฐ” 7๋ถ€ํ„ฐ๋Š” ๊ณ ์„ฑ๋Šฅ ๋ณ‘๋ ฌ ๋ถ„ํ•ด ํ”„๋ ˆ์ž„์›Œํฌ์ธ ํฌํฌ-์กฐ์ธ(fork-join) ํŒจํ‚ค์ง€๋ฅผ ์ถ”๊ฐ€
  • ์ž๋ฐ” 8๋ถ€ํ„ฐ๋Š” parallel ๋ฉ”์„œ๋“œ๋งŒ ํ•œ ๋ฒˆ ํ˜ธ์ถœํ•˜๋ฉด ํŒŒ์ดํ”„๋ผ์ธ์„ ๋ณ‘๋ ฌ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋Š” ์ŠคํŠธ๋ฆผ์„ ์ง€์›

java.util.concurrent ํŒจํ‚ค์ง€๊ฐ€ ๋“ฑ์žฅ

  • ์ด ํŒจํ‚ค์ง€๋Š” Executor framework ๋ผ๊ณ  ํ•˜๋Š” ์ธํ„ฐํŽ˜์ด์Šค ๊ธฐ๋ฐ˜์˜ ์œ ์—ฐํ•œ ํ…Œ์Šคํฌ ์‹คํ–‰ ๊ธฐ๋Šฅ์„ ๋‹ด๊ณ  ์žˆ๋‹ค.
  • ๋ชจ๋“  ๋ฉด์—์„œ ๋›ฐ์–ด๋‚œ ์ž‘์—… ํ๋ฅผ ๋‹ค์Œ์˜ ๋‹จ ํ•œ์ค„๋กœ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ๋‹ค.
  • ์ž๋ฐ”๋Š” ์Šค๋ ˆ๋“œ ํ’€์„ ์ƒ์„ฑํ•˜๊ณ  ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก java.util.concurrent.ExecutorService ์ธํ„ฐํŽ˜์ด์Šค์™€ Executors ํด๋ž˜์Šค ๋ฉ”์†Œ๋“œ ์ค‘ newCachedThreadPool๊ณผ newFixedThreadPool ๋ฉ”์†Œ๋“œ๋ฅผ ์ œ๊ณตํ•˜๊ณ  ์žˆ๋‹ค.
ExcutorService exec  = Executors.newSingleThreadExcutor();

// ๋‹ค์Œ์€ ์ด Excutor์— ์‹คํ–‰ํ•  ํƒœ์Šคํฌ(task; ์ž‘์—…)๋ฅผ ๋„˜๊ธฐ๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.

exec.execute(runnable);

// ๋‹ค์Œ์€ Excutor๋ฅผ ์šฐ์•„ํ•˜๊ฒŒ ์ข…๋ฃŒ์‹œํ‚ค๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค(์ด ์ž‘์—…์ด ์‹คํŒจํ•˜๋ฉด VM ์ž์ฒด๊ฐ€ ์ข…๋ฃŒ๋˜์ง€ ์•Š์„ ๊ฒƒ์ด๋‹ค)

exec.shutdown();   
  • ExecutorService์˜ ๊ธฐ๋Šฅ์€ ์ด ์™ธ์—๋„ ๋งŽ๋‹ค. ๋‹ค์Œ์€ ExecutorService์˜ ์ฃผ์š” ๊ธฐ๋Šฅ

ํŠน์ • ํƒœ์Šคํฌ๊ฐ€ ์™„๋ฃŒ ๋˜๊ธฐ๋ฅผ ๊ธฐ๋‹ค๋ฆฐ๋‹ค. (์ฝ”๋“œ 79-2์—์„œ ๋ณธ get๋ฉ”์„œ๋“œ)

ํƒœ์Šคํฌ ๋ชจ์Œ ์ค‘ ์•„๋ฌด๊ฒƒ ํ•˜๋‚˜ (invokeAny ๋ฉ”์„œ๋“œ) ํ˜น์€ ๋ชจ๋“  ํƒœ์Šคํฌ(invoke All ๋ฉ”์„œ๋“œ)๊ฐ€ ์™„๋ฃŒ๋˜๊ธฐ๋ฅผ ๊ธฐ๋‹ค๋ฆฐ๋‹ค.

ExecutorService๊ฐ€ ์ข…๋ฃŒํ•˜๊ธฐ๋ฅผ ๊ธฐ๋‹ค๋ฆฐ๋‹ค. (aWaitTermination ๋ฉ”์„œ๋“œ).

์™„๋ฃŒ๋œ ํƒœ์Šคํฌ๋“ค์˜ ๊ฒฐ๊ณผ๋ฅผ ์ฐจ๋ก€๋กœ ๋ฐ›๋Š”๋‹ค. (ExecutorCompletionService ์ด์šฉ).

ํƒœ์Šคํฌ๋ฅผ ํŠน์ • ์‹œ๊ฐ„์— ํ˜น์€ ์ฃผ๊ธฐ์ ์œผ๋กœ ์‹คํ–‰ํ•˜๊ฒŒ ํ•œ๋‹ค. (ScheduledThreadPoolExecutor ์ด์šฉ).

ํ๋ฅผ ๋‘˜ ์ด์ƒ์˜ ์Šค๋ ˆ๋“œ๊ฐ€ ์ฒ˜๋ฆฌํ•˜๊ฒŒ ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ๊ฐ„๋‹จํžˆ ๋‹ค๋ฅธ ์ •์  ํŒฉํ„ฐ๋ฆฌ๋ฅผ ์ด์šฉํ•˜์—ฌ ๋‹ค๋ฅธ ์ข…๋ฅ˜์˜ ์‹คํ–‰์ž ์„œ๋น„์Šค(์Šค๋ ˆ๋“œ ํ’€)๋ฅผ ์ƒ์„ฑํ•˜๋ฉด ๋œ๋‹ค.

์Šค๋ ˆ๋“œ ํ’€์˜ ์Šค๋ ˆ๋“œ ๊ฐœ์ˆ˜๋Š” ๊ณ ์ •ํ•  ์ˆ˜๋„ ์žˆ๊ณ  ํ•„์š”์— ๋”ฐ๋ผ ๋Š˜์–ด๋‚˜๊ฑฐ๋‚˜ ์ค„์–ด๋“ค๊ฒŒ ์„ค์ •ํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

์šฐ๋ฆฌ์—๊ฒŒ ํ•„์š”ํ•œ ์‹คํ–‰์ž ๋Œ€๋ถ€๋ถ„ java.util.concurrent.Executors์˜ ์ •์  ํŒฉํ„ฐ๋ฆฌ๋“ค์„ ์ด์šฉํ•ด ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ์ด๋‹ค. ํ‰๋ฒ”ํ•˜์ง€ ์•Š์€ ์‹คํ–‰์ž๋ฅผ ์›ํ•œ๋‹ค๋ฉด ThreadPoolExecutor ํด๋ž˜์Šค๋ฅผ ์ง์ ‘ ์‚ฌ์šฉํ•ด๋„ ๋œ๋‹ค. ์ด ํด๋ž˜์Šค๋กœ๋Š” ์Šค๋ ˆ๋“œ ํ’€ ๋™์ž‘์„ ๊ฒฐ์ •ํ•˜๋Š” ๊ฑฐ์˜ ๋ชจ๋“  ์†์„ฑ์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

  • ExecutorService๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ์— ๊นŒ๋‹ค๋กœ์šด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜๋„ ์žˆ๋‹ค.
  • ์ž‘์€ ํ”„๋กœ๊ทธ๋žจ์ด๋‚˜ ๊ฐ€๋ฒผ์šด ์„œ๋ฒ„๋ผ๋ฉด Executors.newCachedThreadPool์ด ์ผ๋ฐ˜์ ์œผ๋กœ ์ข‹์€ ์„ ํƒ์ผ ๊ฒƒ์ด๋‹ค.
  • ์ผ๋ฐ˜์ ์œผ๋กœ ํŠน๋ณ„ํžˆ ์„ค์ •ํ•  ๊ฒŒ ์—†๊ณ  ์ผ๋ฐ˜์ ์ธ ์šฉ๋„์— ์ ํ•ฉํ•˜๊ฒŒ ๋™์ž‘ํ•œ๋‹ค.
  • CachedThreadPool์€ ๋ฌด๊ฑฐ์šด ํ”„๋กœ๋•์…˜ ์„œ๋ฒ„์—๋Š” ์ข‹์ง€ ๋ชปํ•˜๋‹ค.
  • CachedThreadPool์—์„œ๋Š” ์š”์ฒญ๋ฐ›์€ ํƒœ์Šคํฌ๋“ค์ด ํ์— ์Œ“์ด์ง€ ์•Š๊ณ  ์ฆ‰์‹œ ์Šค๋ ˆ๋“œ์— ์œ„์ž„๋ผ ์‹คํ–‰๋œ๋‹ค. ๊ฐ€์šฉํ•œ ์Šค๋ ˆ๋“œ๊ฐ€ ์—†๋‹ค๋ฉด ์ƒˆ๋กœ ํ•˜๋‚˜๋ฅผ ์ƒ์„ฑํ•œ๋‹ค.
  • ์„œ๋ฒ„๊ฐ€ ์•„์ฃผ ๋ฌด๊ฒ๋‹ค๋ฉด CPU ์ด์šฉ๋ฅ ์ด 100%๋กœ ์น˜๋‹ซ๊ณ  ์ƒˆ๋กœ์šด ํƒœ์Šคํฌ๊ฐ€ ๋„์ฐฉํ•˜๋Š” ์กฑ์กฑ ๋˜ ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ๋ฅผ ์ƒ์„ฑํ•˜๋ฉฐ ์ƒํ™ฉ์„ ๋”์šฑ ์•…ํ™”์‹œํ‚จ๋‹ค.

์ž‘์—… ํ๋ฅผ ์†์ˆ˜ ๋งŒ๋“œ๋Š” ์ผ์€ ์‚ผ๊ฐ€์•ผํ•˜๊ณ  ์Šค๋ ˆ๋“œ๋ฅผ ์ง์ ‘ ๋‹ค๋ฃจ๋Š” ๊ฒƒ๋„ ์ผ๋ฐ˜์ ์œผ๋กœ ์‚ผ๊ฐ€์•ผ ํ•œ๋‹ค.

  • ์Šค๋ ˆ๋“œ๋ฅผ ์ง์ ‘ ๋‹ค๋ฃจ๋ฉด Thread๊ฐ€ ์ž‘์—… ๋‹จ์œ„์™€ ์ˆ˜ํ–‰ ๋งค์ปค๋‹ˆ์ฆ˜ ์—ญํ• ์„ ๋ชจ๋‘ ์ˆ˜ํ–‰ํ•˜๊ฒŒ ๋œ๋‹ค.
  • ๋ฐ˜๋ฉด Executor Framework์—์„œ๋Š” ์ž‘์—… ๋‹จ์œ„์™€ ์‹คํ–‰ ๋ฉ”์ปค๋‹ˆ์ฆ˜์ด ๋ถ„๋ฆฌ๋œ๋‹ค.
  • ์ž‘์—… ๋‹จ์œ„๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ํ•ต์‹ฌ ์ถ”์ƒ ๊ฐœ๋…์ด ํƒœ์Šคํฌ๋‹ค.

Runnable, Callable (Runnable๊ณผ ๋น„์Šทํ•˜์ง€๋งŒ ๊ฐ’์„ ๋ฐ˜ํ™˜ํ•˜๊ณ  ์ž„์˜์˜ ์˜ˆ์™ธ๋ฅผ ๋˜์งˆ ์ˆ˜ ์žˆ๋‹ค.)

  • Runable ๋˜๋Š” Callable ๊ตฌํ˜„ ํด๋ž˜์Šค๋กœ ์ž‘์—…์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ๋‘˜์˜ ์ฐจ์ด๋Š” ์ž‘์—…์ด ๋๋‚œ ํ›„ ๋ฆฌํ„ด ๊ฐ’์ด ์žˆ๋ƒ ์—†๋Š๋ƒ์˜ ์ฐจ์ด์ž…๋‹ˆ๋‹ค.
  • ํƒœ์Šคํฌ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ์ผ๋ฐ˜์ ์ธ ๋ฉ”์ปค๋‹ˆ์ฆ˜์ด ๋ฐ”๋กœ ExcutorService์ด๋‹ค. ํƒœ์Šคํฌ ์ˆ˜ํ–‰์„ ์‹คํ–‰์ž ์„œ๋น„์Šค์— ๋งก๊ธฐ๋ฉด ์›ํ•˜๋Š” ํƒœ์Šคํฌ ์ˆ˜ํ–‰ ์ •์ฑ…์„ ์„ ํƒํ•  ์ˆ˜ ์žˆ๊ณ  ์ƒ๊ฐ์ด ๋ฐ”๋€Œ๋ฉด ์–ธ์ œ๋“  ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋‹ค.

์ž๋ฐ” 7์ด ๋˜๋ฉด์„œ Executor Framework๋Š” Fork-join ํƒœ์Šคํฌ๋ฅผ ์ง€์›ํ•˜๋„๋ก ํ™•์žฅ

  1. ํฌํฌ-์กฐ์ธ ํƒœ์Šคํฌ๋Š” ํฌํฌ-์กฐ์ธ ํ’€์ด๋ผ๋Š” ํŠน๋ณ„ํ•œ ์‹คํ–‰์ž ์„œ๋น„์Šค๊ฐ€ ์‹คํ–‰ํ•ด์ค€๋‹ค.
  2. ํฌํฌ-์กฐ์ธ ํƒœ์Šคํฌ, ์ฆ‰ ForkJoinTask์˜ ์ธ์Šคํ„ด์Šค๋Š” ์ž‘์€ ํ•˜์œ„ ํƒœ์Šคํฌ๋กœ ๋‚˜๋‰  ์ˆ˜ ์žˆ๊ณ , ForkJoinPool์„ ๊ตฌ์„ฑํ•˜๋Š” ์Šค๋ ˆ๋“œ๋“ค์ด ์ด ํƒœ์Šคํฌ๋“ค์„ ์ฒ˜๋ฆฌํ•˜๋ฉฐ ์ผ์„ ๋จผ์ € ๋๋‚ธ ์Šค๋ ˆ๋“œ๋Š” ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ์˜ ๋‚จ์€ ํƒœ์Šคํฌ๋ฅผ ๊ฐ€์ ธ์™€ ๋Œ€์‹  ์ฒ˜๋ฆฌํ•  ์ˆ˜๋„ ์žˆ๋‹ค.
  3. ์ด๋ ‡๊ฒŒํ•˜์—ฌ ๋ชจ๋“  ์Šค๋ ˆ๋“œ๊ฐ€ ๋ฐ”์˜๊ฒŒ ์›€์ง์—ฌ CPU๋ฅผ ์ตœ๋Œ€ํ•œ ํ™œ์šฉํ•˜๋ฉด์„œ ๋†’์€ ์ฒ˜๋ฆฌ๋Ÿ‰๊ณผ ๋‚ฎ์€ ์ง€์—ฐ์‹œ๊ฐ„์„ ๋‹ฌ์„ฑํ•œ๋‹ค.

ํ•ต์‹ฌ ์ •๋ฆฌ

๋ณ‘๋ ฌ ์ŠคํŠธ๋ฆผ(์•„์ดํ…œ 48: ์ŠคํŠธ๋ฆผ ๋ณ‘๋ ฌํ™”)์„ ์ด์šฉํ•˜๋ฉด ์ ์€ ๋…ธ๋ ฅ์œผ๋กœ ๊ทธ ์ด์ ์„ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค.
๋™์‹œ์„ฑ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ํ•  ๋•Œ๋Š” ์•ˆ์ •์„ฑ๊ณผ ์‘๋‹ต๊ฐ€๋Šฅ ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ์• ์จ์•ผ ํ•œ๋‹ค. (์•„์ดํ…œ 48)