#java, #synchronized, #monitor

๐Ÿ”’ Java ๋กœ ๋™๊ธฐํ™”๋ฅผ ํ•ด๋ณด์ž!

์ด ๊ธ€์—์„œ๋Š” ์ƒํ˜ธ๋ฐฐ์ œ๋ฅผ ํ†ตํ•œ ๋™๊ธฐํ™”๋ฅผ ์•Œ์•„๋ณผ ๊ฒƒ์ด๋‹ค. ๋™๊ธฐํ™”๋Š” ํ”„๋กœ์„ธ์Šค(์Šค๋ ˆ๋“œ)๊ฐ€ ์ˆ˜ํ–‰๋˜๋Š” ์‹œ์ ์„ ์กฐ์ ˆํ•˜์—ฌ ์„œ๋กœ๊ฐ€ ์•Œ๊ณ  ์žˆ๋Š” ์ •๋ณด๊ฐ€ ์ผ์น˜ํ•˜๋Š” ๊ฒƒ์ธ๋ฐ, ์‰ฝ๊ฒŒ ๋งํ•ด ํ”„๋กœ์„ธ์Šค ๊ฐ„ ๋ฐ์ดํ„ฐ๊ฐ€ ์ผ์น˜ํ•˜๋„๋ก ํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ์ด๋Ÿฌํ•œ ๋™๊ธฐํ™” ๋ฉ”์ปค๋‹ˆ์ฆ˜์ธ ์ƒํ˜ธ๋ฐฐ์ œ๋Š” ํ”„๋กœ์„ธ์Šค๋“ค์ด ํ•„์š”๋กœ ํ•˜๋Š” ์ž์›์— ๋Œ€ํ•ด ๋ฐฐํƒ€์ ์ธ ํ†ต์ œ๊ถŒ์„ ์š”๊ตฌํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ์‰ฝ๊ฒŒ ๋งํ•ด ํ•˜๋‚˜์˜ ํ”„๋กœ์„ธ์Šค๊ฐ€ ๊ณต์œ ์ž์›์„ ์‚ฌ์šฉํ•  ๋•Œ ๋‹ค๋ฅธ ํ”„๋กœ์„ธ์Šค๊ฐ€ ๋™์ผํ•œ ๊ณต์œ ์ž์›์— ์ ‘๊ทผํ•  ์ˆ˜ ์—†๋„๋ก ํ†ต์ œํ•˜๋Š” ๊ฒƒ์„ ๋œปํ•œ๋‹ค. ์ƒํ˜ธ๋ฐฐ์ œ ๋ฐฉ๋ฒ•์œผ๋กœ๋Š” Mutex, Semaphore ๋ฐฉ์‹์ด ์‚ฌ์šฉ๋œ๋‹ค. Java ์—์„œ๋Š” Monitor ๋ผ๋Š” ๋„๊ตฌ๋ฅผ ํ†ตํ•ด ๊ฐ์ฒด์— Lock ์„ ๊ฑธ์–ด ์ƒํ˜ธ๋ฐฐ์ œ๋ฅผ ํ•  ์ˆ˜ ์žˆ๋‹ค. Monitor ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์–ด๋–ค ์ ์ด ์ข‹์€์ง€ ์•Œ์•„๋ณด๊ณ  ์ง์ ‘ ์‚ฌ์šฉํ•ด๋ณด์ž.

๋จผ์ € Mutex, Semaphore ๊ฐœ๋…์„ ๊ฐ„๋‹จํ•˜๊ฒŒ ์‚ดํŽด๋ณด์ž.

Mutex

์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋Š” ํ™˜๊ฒฝ์—์„œ ์ž์›์— ๋Œ€ํ•œ ์ ‘๊ทผ์— ์ œํ•œ์„ ๊ฐ•์ œํ•˜๊ธฐ ์œ„ํ•œ ๋™๊ธฐํ™” ๋ฉ”์ปค๋‹ˆ์ฆ˜์ด๋‹ค. ํŠน์ง•์„ ์‚ดํŽด๋ณด๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  • Boolean ํƒ€์ž…์˜ Lock ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. ๋”ฐ๋ผ์„œ 1๊ฐœ์˜ ๊ณต์œ ์ž์›์— ๋Œ€ํ•œ ์ ‘๊ทผ์„ ์ œํ•œํ•œ๋‹ค.
  • ๊ณต์œ ์ž์›์„ ์‚ฌ์šฉ ์ค‘์ธ ์Šค๋ ˆ๋“œ๊ฐ€ ์žˆ์„ ๋•Œ, ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ๊ฐ€ ๊ณต์œ ์ž์›์— ์ ‘๊ทผํ•œ๋‹ค๋ฉด Blocking ํ›„ ๋Œ€๊ธฐ ํ๋กœ ๋ณด๋‚ธ๋‹ค.
  • Lock ์„ ๊ฑด ์Šค๋ ˆ๋“œ๋งŒ Lock ์„ ํ•ด์ œํ•  ์ˆ˜ ์žˆ๋‹ค.

Semaphore

๋ฉ€ํ‹ฐํ”„๋กœ๊ทธ๋ž˜๋ฐ ํ™˜๊ฒฝ์—์„œ ๋‹ค์ˆ˜์˜ ํ”„๋กœ์„ธ์Šค๋‚˜ ์Šค๋ ˆ๋“œ๊ฐ€ n ๊ฐœ์˜ ๊ณต์œ  ์ž์›์— ๋Œ€ํ•œ ์ ‘๊ทผ์„ ์ œํ•œํ•˜๋Š” ๋ฐฉ๋ฒ•์œผ๋กœ ์‚ฌ์šฉ๋˜๋Š” ๋™๊ธฐํ™” ๊ธฐ๋ฒ•์ด๋‹ค.

  • ์„ธ๋งˆํฌ์–ด ๋ณ€์ˆ˜๋ฅผ ํ†ตํ•ด wait, signal ์„ ๊ด€๋ฆฌํ•œ๋‹ค. ์„ธ๋งˆํฌ์–ด ๋ณ€์ˆ˜๋Š” 0 ์ด์ƒ์˜ ์ •์ˆ˜ํ˜• ๋ณ€์ˆ˜๋ฅผ ๊ฐ–๋Š”๋‹ค.
  • n ๊ฐœ์˜ ๊ณต์œ ์ž์›์— ๋Œ€ํ•œ ์ ‘๊ทผ์„ ์ œํ•œํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ์ด๋ฅผ ๊ณ„์ˆ˜ ์„ธ๋งˆํฌ์–ด๋ผ๊ณ  ํ•œ๋‹ค.
  • ์ ‘๊ทผ ๊ฐ€๋Šฅํ•œ ๊ณต์œ  ์ž์›์˜ ์ˆ˜๊ฐ€ 1๊ฐœ์ผ ๋•Œ๋Š” ์ด์ง„ ์„ธ๋งˆํฌ์–ด๋กœ ๋ฎคํ…์Šค์ฒ˜๋Ÿผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ํ์— ์—ฐ๊ฒฐ๋œ ์Šค๋ ˆ๋“œ๋ฅผ ๊นจ์šฐ๋Š” ๋ฐฉ์‹์— ๋”ฐ๋ผ ๊ฐ•์„ฑ ์„ธ๋งˆํฌ์–ด(ํ์— ์—ฐ๊ฒฐ๋œ ์Šค๋ ˆ๋“œ๋ฅผ ๊นจ์šธ ๋•Œ FIFO ์ •์ฑ…), ์•ฝ์„ฑ ์„ธ๋งˆํฌ์–ด(ํ์— ์—ฐ๊ฒฐ๋œ ์Šค๋ ˆ๋“œ๋ฅผ ๊นจ์šธ ๋•Œ ์ˆœ์„œ๋ฅผ ํŠน๋ณ„ํžˆ ๋ช…์‹œํ•˜์ง€ ์•Š์Œ)๋กœ ๊ตฌ๋ถ„๋œ๋‹ค.
  • Lock ์„ ๊ฑธ์ง€ ์•Š์€ ์Šค๋ ˆ๋“œ๋„ Signal ์„ ๋ณด๋‚ด Lock ์„ ํ•ด์ œํ•  ์ˆ˜ ์žˆ๋‹ค.

๋™๊ธฐํ™” ๋ฉ”์ปค๋‹ˆ์ฆ˜

Mutex, Semaphore ๋Š” ์ƒํ˜ธ๋ฐฐ์ œ๋ฅผ ์œ„ํ•œ ๋™๊ธฐํ™” ๊ฐœ๋…์ด๋‹ค. Framework, Library ์—์„œ๋Š” ์ด ๊ฐœ๋…์„ ๋ฐ”ํƒ•์œผ๋กœ ๊ตฌํ˜„๋œ ์ƒํ˜ธ๋ฐฐ์ œ ๋„๊ตฌ๋ฅผ ์ œ๊ณตํ•œ๋‹ค. ๋ฌผ๋ก  C ์–ธ์–ด ๊ฐ™์€ ์–ธ์–ด๋Š” ์ œ๊ณตํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์ง์ ‘ ์ฝ”๋“œ๋ฅผ ๊ตฌํ˜„ํ•ด์•ผ ํ•˜๋Š” ๋ฒˆ๊ฑฐ๋กœ์›€์ด ์žˆ๋‹ค. ๋˜ํ•œ Semaphore ๋Š” ์™„๋ฒฝํ•œ ์ƒํ˜ธ๋ฐฐ์ œ๋ฅผ ์ œ๊ณตํ•œ๋‹ค๊ณ  ํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— ์ด๋ฅผ ๋ณด์™„๊นŒ์ง€ ํ•ด๋‘” Monitor ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํ›จ์”ฌ ์‰ฝ๊ฒŒ ๋™๊ธฐํ™”๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

Monitor

์ž„๊ณ„ ๊ตฌ์—ญ์„ ์ง€์ผœ๋‚ด๊ธฐ ์œ„ํ•œ ๋ฐฉ๋ฒ•์ธ ์ƒํ˜ธ ๋ฐฐ์ œ๋ฅผ ํ”„๋กœ๊ทธ๋žจ์œผ๋กœ ๊ตฌํ˜„ํ•œ ๊ฒƒ์ด๋‹ค. ์„ธ๋งˆํฌ์–ด๋Š” wait & signal ์—ฐ์‚ฐ ์ˆœ์„œ๋ฅผ ๋ฐ”๊ฟ”์„œ ์‹คํ–‰ํ•˜๊ฑฐ๋‚˜ ๋‘˜ ์ค‘ ํ•˜๋‚˜๋ผ๋„ ์ƒ๋žตํ•˜๋ฉด ์ƒํ˜ธ๋ฐฐ์ œ๋ฅผ ์œ„๋ฐ˜ํ•˜๋Š” ์ƒํ™ฉ์ด๋‚˜ ๊ต์ฐฉ ์ƒํƒœ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค. wait & signal ์—ฐ์‚ฐ์ด ํ”„๋กœ๊ทธ๋žจ ์ „์ฒด์— ๊ตฌ์„ฑ๋˜์–ด ์žˆ์œผ๋ฉด ์„ธ๋งˆํฌ์–ด์˜ ์˜ํ–ฅ์ด ๋ฏธ์น˜๋Š” ๊ณณ์ด ์–ด๋”˜์ง€ ํŒŒ์•…ํ•˜๊ธฐ ์–ด๋ ต๊ธฐ ๋•Œ๋ฌธ์— ์„ธ๋งˆํฌ์–ด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ”„๋กœ๊ทธ๋žจ์„ ๊ตฌํ˜„ํ•˜๊ธฐ ์–ด๋ ต๋‹ค. ์ด๋Ÿฌํ•œ ๋‹จ์ ์„ ๊ทน๋ณตํ•˜๊ธฐ ์œ„ํ•ด ๋ชจ๋‹ˆํ„ฐ๊ฐ€ ๋“ฑ์žฅํ–ˆ๋‹ค. ๋ชจ๋‹ˆํ„ฐ๋Š” ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด ์ˆ˜์ค€์—์„œ ์ œ๊ณต๋œ๋‹ค. ๋Œ€ํ‘œ์ ์œผ๋กœ Java ์—์„œ ์ œ๊ณตํ•œ๋‹ค. ์ˆœ์ฐจ์ ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ณต์œ  ์ž์› ํ˜น์€ ๊ณต์œ  ์ž์› ๊ทธ๋ฃน์„ ํ• ๋‹นํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋œ๋‹ค. ๋ชจ๋‹ˆํ„ฐ๋Š” ์ด์ง„ ์„ธ๋งˆํฌ์–ด๋งŒ ๊ฐ€๋Šฅํ•˜๋‹ค. ๋ชจ๋‹ˆํ„ฐ๋ฅผ ํ†ตํ•ด ํ”„๋กœ์„ธ์Šค๊ฐ€ ์ž์›์— ์ ‘๊ทผํ•˜๋Š” ๋ฐฉ์‹์„ ์ด๋ฏธ์ง€๋กœ ๋ณด๋ฉด ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

image

๊ณต์œ  ์ž์›์— ์ ์œ  ์ค‘์ธ ํ”„๋กœ์„ธ์Šค(์Šค๋ ˆ๋“œ)๋Š” Lock ์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค. ๊ณต์œ  ์ž์›์„ ์ ์œ  ์ค‘์ธ ํ”„๋กœ์„ธ์Šค(์Šค๋ ˆ๋“œ)๊ฐ€ ์žˆ๋Š” ์ƒํ™ฉ์—์„œ ๋‹ค๋ฅธ ํ”„๋กœ์„ธ์Šค(์Šค๋ ˆ๋“œ)๊ฐ€ ๊ณต์œ  ์ž์›์— ์ ‘๊ทผํ•˜๋ ค๊ณ  ํ•˜๋ฉด ์™ธ๋ถ€ ๋ชจ๋‹ˆํ„ฐ ์ค€๋น„ ํ์—์„œ ์ง„์ž…์„ wait ํ•œ๋‹ค. Monitor ๋Š” Semaphore ์ฒ˜๋Ÿผ signal ์—ฐ์‚ฐ์„ ๋ณด๋‚ด๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์กฐ๊ฑด ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํŠน์ • ์กฐ๊ฑด์— ๋Œ€ํ•ด ๋Œ€๊ธฐ ํ์— signal ์„ ๋ณด๋‚ด ์ž‘์—…์„ ์‹œ์ž‘์‹œํ‚จ๋‹ค.

Synchronized

Java ์˜ synchronized ํ‚ค์›Œ๋“œ๋Š” ์Šค๋ ˆ๋“œ ๋™๊ธฐํ™”๋ฅผ ํ•  ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ๋Œ€ํ‘œ์ ์ธ ๊ธฐ๋ฒ•์ด๋‹ค. ์ž๋ฐ”์˜ ๋ชจ๋“  ์ธ์Šคํ„ด์Šค๋Š” Monitor ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฉฐ(Object ๋‚ด๋ถ€) Monitor ๋ฅผ ํ†ตํ•ด Thread ๋™๊ธฐํ™”๋ฅผ ์ˆ˜ํ–‰ํ•œ๋‹ค. synchronized ํ‚ค์›Œ๋“œ๊ฐ€ ๋ถ™์€ ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๋ฉด Lock ์„ ๊ฐ€์ง€๊ณ  ์žˆ์–ด์•ผ ํ•œ๋‹ค.

synchronized ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์œผ๋กœ๋Š” ๋ฉ”์„œ๋“œ ์•ž์— ํ‚ค์›Œ๋“œ ๋ช…์‹œ, ์ธ์Šคํ„ด์Šค๋กœ ์‚ฌ์šฉํ•˜๊ธฐ๊ฐ€ ์žˆ๋‹ค. ๋™๊ธฐํ™”๊ฐ€ ํ•„์š”ํ•œ ๋ฉ”์„œ๋“œ ์•ž์— synchronized ํ‚ค์›Œ๋“œ๋งŒ ๋ถ™์—ฌ์ฃผ๋ฉด ํŽธ๋ฆฌํ•˜๊ฒŒ ๋™๊ธฐํ™”๋ฅผ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ์ธ์Šคํ„ด์Šค๋กœ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ๋ฉ”์„œ๋“œ ๋‚ด๋ถ€์—์„œ synchronized (๋ฉ”์„œ๋“œ) { ๊ตฌํ˜„ } ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

wait, notify

Monitor ์—๋Š” Condition Variable ์ด ์žˆ๋Š”๋ฐ ์ด๋ฅผ ํ†ตํ•ด wait(), notify() ๋ฉ”์„œ๋“œ๊ฐ€ ๊ตฌํ˜„๋˜์–ด ์žˆ๋‹ค.

Lock ์„ ๊ฐ€์ง„ ์Šค๋ ˆ๋“œ๊ฐ€ ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ์— Lock ์„ ๋„˜๊ฒจ์ค€ ์ดํ›„์— ๋Œ€๊ธฐํ•ด์•ผ ํ•œ๋‹ค๋ฉด wait() ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋Œ€๊ธฐ ์ค‘์ธ ์ž„์˜์˜ ์Šค๋ ˆ๋“œ๋ฅผ ๊นจ์šฐ๋ ค๋ฉด notify() ๋ฅผ ํ†ตํ•ด ๊นจ์šธ ์ˆ˜ ์žˆ๋‹ค. ๋Œ€๊ธฐ ์ค‘์ธ ๋ชจ๋“  ์Šค๋ ˆ๋“œ๋ฅผ ๊นจ์šฐ๋ ค๋ฉด notifyAll() ์„ ํ†ตํ•ด ๊นจ์šธ ์ˆ˜ ์žˆ๋Š”๋ฐ, ์ด ๊ฒฝ์šฐ์—๋Š” ํ•˜๋‚˜์˜ ์Šค๋ ˆ๋“œ๋งŒ Lock ์„ ํš๋“ํ•˜๊ณ  ๋‚˜๋จธ์ง€ ์Šค๋ ˆ๋“œ๋Š” ๋‹ค์‹œ ๋Œ€๊ธฐ ์ƒํƒœ์— ๋“ค์–ด๊ฐ„๋‹ค.

๋™๊ธฐํ™”๋ฅผ ๊ฒฝํ—˜ํ•ด ๋ณด์ž!

๋จผ์ € synchronized ๋ฅผ ์ด์šฉํ•œ ๋ฉ”์„œ๋“œ ๋™๊ธฐํ™”์™€ ๋ธ”๋Ÿญ ๋™๊ธฐํ™”๋ฅผ ์‚ดํŽด๋ณธ๋‹ค.

์ด ๋ธŒ๋ผ์šฐ์ €์˜ ํŠน์ง•์„ ์‚ดํŽด๋ณด์ž.

  • ์ตœ๋Œ€ 5๊ฐœ์˜ ํƒญ์ด ํ™œ์„ฑํ™”๋  ์ˆ˜ ์žˆ๋‹ค.
  • 6๊ฐœ ์ด์ƒ์˜ ํƒญ์ด ๋™์‹œ์— ์ผœ์ง€๊ฒŒ ๋˜๋ฉด ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ๊ฐ•์ œ ์ข…๋ฃŒ๋œ๋‹ค.
  • ์ƒˆ๋กœ์šด ํƒญ์ด ์ผœ์ง€๋Š” ์‹œ๊ฐ„์€ 0~1์ดˆ๊ฐ€ ๊ฑธ๋ฆฐ๋‹ค.
  • ์ƒˆ๋กœ์šด ํƒญ์ด ์ผœ์ง€๋Š” ๋กœ๋”ฉ์‹œ๊ฐ„ ๋™์•ˆ์€ ํ˜„์žฌ ํ™œ์„ฑํ™”๋œ ํƒญ ์ˆ˜๊ฐ€ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š๋Š”๋‹ค.

    • ๋ธŒ๋ผ์šฐ์ € ๋กœ๋”ฉ์ด ๋๋‚œ ํ›„(1์ดˆ ํ›„) ํƒญ ์ˆ˜๊ฐ€ ๊ฐฑ์‹ ๋œ๋‹ค๋Š” ๋œป์ด๋‹ค. (4๊ฐœ -> ์ƒˆ๋กœ์šด ํƒญ ๋กœ๋”ฉ(1์ดˆ) -> 1์ดˆ ํ›„ 5๊ฐœ)
    • ์ฆ‰, ๋กœ๋”ฉ ์ค‘์— ์ƒˆ๋กœ์šด ํƒญ์ด โ€˜์•„์ง 4๊ฐœ๋ฐ–์— ํ™œ์„ฑํ™”๋˜์ง€ ์•Š์•˜๋„ค?โ€™ ๋ผ๊ณ  ํŒ๋‹จํ•˜๊ณ  ์ƒˆ๋กœ์šด ํƒญ์ด ๋˜ ์ผœ์งˆ ์ˆ˜ ์žˆ๋‹ค๋Š” ๋œป์ด๋‹ค.

๋น„๋™๊ธฐ(๊ฒฐ๊ณผ๋ฅผ ์ฃผ๊ธฐ ์ „์— ๋‹ค๋ฅธ ์ž‘์—…์ด ์ด๋ฃจ์–ด์ง€๋Š” ๊ฒƒ)๋กœ ์ฒ˜๋ฆฌ๊ฐ€ ๋œ๋‹ค๋ฉด ์ƒˆ๋กœ์šด ํƒญ์ด ์ถ”๊ฐ€๋˜๊ธฐ ์œ„ํ•ด ๋กœ๋”ฉ ์ค‘์ธ ์ƒํ™ฉ์—์„œ ๋˜ ๋‹ค๋ฅธ ํƒญ์ด ์ถ”๊ฐ€๋˜๋Š” ๊ฒƒ์„ ์‹œ๋„ํ•œ๋‹ค๋ฉด ๊ณง์ด์–ด ๊ฐ•์ œ ์ข…๋ฃŒ๊ฐ€ ๋˜๋Š” ์ƒํ™ฉ์ด ๋ฐœ์ƒํ•˜๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค. ๊ทธ ๋•Œ๋ฌธ์— ์ƒˆ๋กœ์šด ํƒญ์ด ์ถ”๊ฐ€๋˜๋Š” ์ƒํ™ฉ์—๋Š” ๋‹ค๋ฅธ ํƒญ์ด ์ถ”๊ฐ€๋˜๋Š” ์ž‘์—…์„ ๋ง‰์„ ํ•„์š”๊ฐ€ ์žˆ๋‹ค.

์„ธ ๊ฐœ์˜ ํด๋ž˜์Šค๋ฅผ ์ค€๋น„ํ•œ๋‹ค.

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

public class Computer {

    public static void main(String[] args) {
        final WebBrowser webBrowser = new WebBrowser(5);

        final Thread threadA = new Thread(new WebSite("Google", webBrowser));
        final Thread threadB = new Thread(new WebSite("Naver", webBrowser));
        final Thread threadC = new Thread(new WebSite("Daum", webBrowser));

        threadA.start();
        threadB.start();
        threadC.start();
    }
}

public class WebSite implements Runnable {

    private final String webSiteName;
    private final WebBrowser webBrowser;

    public WebSite(final String webSiteName, final WebBrowser webBrowser) {
        this.webSiteName = webSiteName;
        this.webBrowser = webBrowser;
    }

    @Override
    public void run() {
        // ๋ฉ”์„œ๋“œ ๋ธ”๋Ÿญ ๋™๊ธฐํ™”
        synchronized (this) {
            while (webBrowser.hasSpace()) {
                try {
                    Thread.sleep(new Random().nextInt(1000));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                webBrowser.createNewTab(webSiteName);
            }
        }
    }
}

public class WebBrowser {

    private static final String SPACE = " ";
  
    private final List<String> webSiteNames = new ArrayList<>();
    private final int maxWebCount;

    public WebBrowser(final int maxWebCount) {
        this.maxWebCount = maxWebCount;
    }

    // ๋ฉ”์„œ๋“œ ๋™๊ธฐํ™”
    public synchronized void createNewTab(final String webSiteName) {
        try {
            if (full()) {
                return;
            }
            System.out.println(webSiteName + " ์‚ฌ์ดํŠธ๊ฐ€ ์ผœ์ง€๋Š” ์ค‘์ž…๋‹ˆ๋‹ค...");
            Thread.sleep(new Random().nextInt(1000));
            webSiteNames.add(webSiteName);
            showRunningBrowser();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private void showRunningBrowser() {
        if (webSiteNames.size() > maxWebCount) {
            throw new UnsupportedOperationException("ํ˜„์žฌ ๋ธŒ๋ผ์šฐ์ € ํƒญ์ด 6๊ฐœ ์ด์ƒ ํ™œ์„ฑํ™” ๋˜์–ด ๊ฐ•์ œ ์ข…๋ฃŒํ•ฉ๋‹ˆ๋‹ค...");
        }

        System.out.println("โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”");
        System.out.println("โ”‚ โ—† Wilder Web Browser                                                    - โ–ก x โ”‚");
        System.out.println("โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜");

        StringBuilder browserNameLine = new StringBuilder();
        StringBuilder browserUnderLine = new StringBuilder();

        if (webSiteNames.size() > 0) {
            browserNameLine.append("โ”‚");
            browserUnderLine.append("โ””");
        }

        for (int i = 0; i < webSiteNames.size(); i++) {
            browserNameLine.append(generateWebSiteName(webSiteNames.get(i)))
                .append(i + 1)
                .append("   โ”‚");
            browserUnderLine.append("โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜");
        }

        System.out.println(browserNameLine);
        System.out.println(browserUnderLine);
    }

    private String generateWebSiteName(final String name) {
        StringBuilder builder = new StringBuilder();

        if (name.length() > 11) {
            return name.substring(0, 11);
        }

        int space = 11 - name.length();
        int interval = space / 2;

        builder.append(SPACE.repeat(interval))
            .append(name)
            .append(SPACE.repeat(11 - interval - name.length()));

        return builder.toString();
    }

    public boolean hasSpace() {
        return webSiteNames.size() < maxWebCount;
    }

    private boolean full() {
        return !hasSpace();
    }
}

Computer ํด๋ž˜์Šค์˜ main ๋ฉ”์„œ๋“œ๋ฅผ ์‹คํ–‰ํ•ด ๋ณธ๋‹ค. ์œ„์˜ ์˜ˆ์‹œ๋Š” synchronized ํ‚ค์›Œ๋“œ๋ฅผ ํ†ตํ•ด ๊ฐ„๋‹จํ•˜๊ฒŒ ๋ชจ๋‹ˆํ„ฐ๋ฅผ ์‚ฌ์šฉํ•œ ๊ฒƒ์ด๋‹ค. ํ•ด๋‹น ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•ด ๋ณด๋ฉด ์•„๋ž˜์™€ ๋น„์Šทํ•œ ๊ฒฐ๊ณผ๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค.

image

์—ฌ๊ธฐ์„œ ํ•ต์‹ฌ์€ ์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ์—์„œ ์ƒˆ๋กœ์šด ํƒญ์„ ์ถ”๊ฐ€ํ•˜์ง€๋งŒ, ํƒญ์ด 5๊ฐœ๋ฅผ ์ดˆ๊ณผํ•˜์—ฌ ์ƒ์„ฑ๋˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค. synchonized ํ‚ค์›Œ๋“œ๋ฅผ ์ œ๊ฑฐํ•˜๊ณ  ๋‹ค์‹œ ์‹คํ–‰ํ•ด ๋ณด์ž. WebBrowser ํด๋ž˜์Šค์˜ createNewTab ๋ฉ”์„œ๋“œ์™€ WebSite ์˜ run ๋ฉ”์„œ๋“œ์˜ synchronized ๋ถ€๋ถ„์„ ์ œ๊ฑฐํ•œ๋‹ค.

    public void createNewTab(final String webSiteName) {
        try {
            if (full()) {
                return;
            }
            System.out.println(webSiteName + " ์‚ฌ์ดํŠธ๊ฐ€ ์ผœ์ง€๋Š” ์ค‘์ž…๋‹ˆ๋‹ค...");
            Thread.sleep(new Random().nextInt(1000));
            webSiteNames.add(webSiteName);
            showRunningBrowser();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    @Override
    public void run() {
        while (webBrowser.hasSpace()) {
            try {
                Thread.sleep(new Random().nextInt(1000));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            webBrowser.createNewTab(webSiteName);
        }
    }

์œ„์™€ ๊ฐ™์ด ๋ณ€๊ฒฝํ•œ ํ›„ ์‹คํ–‰ํ•ด ๋ณด๋ฉด ์Šค๋ ˆ๋“œ๊ฐ€ ๋น„๋™๊ธฐ๋กœ ์ฒ˜๋ฆฌ๋˜๋ฉด์„œ 6๊ฐœ ์ด์ƒ์˜ ํƒญ์ด ํ™œ์„ฑํ™”๋˜๋ฉฐ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

image

์œ„์˜ ์‹ค์Šต์œผ๋กœ ๋™๊ธฐํ™”๊ฐ€ ์–ด๋–ป๊ฒŒ ์ง„ํ–‰๋˜๋Š”์ง€ ์•Œ์•„๋ณด์•˜๋‹ค. ๋‹ค์Œ์€ wait(), notify() ๋ฅผ ์ด์šฉํ•œ ๋™๊ธฐํ™”๋ฅผ ํ•ด๋ณด์ž.

์กฐ๊ฑด ๋ณ€์ˆ˜๋ฅผ ํ†ตํ•œ ๋ชจ๋‹ˆํ„ฐ ๋™๊ธฐํ™”

wait, notify ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. ์ด์ „์— ์‚ฌ์šฉํ•œ ์ฝ”๋“œ์™€ ๋น„์Šทํ•˜์ง€๋งŒ, ์ผ๋ถ€ ๋ณ€๊ฒฝ ์ ์ด ์žˆ๋‹ค.

  • 3์ดˆ๋งˆ๋‹ค ๊ฐ€์žฅ ๋จผ์ € ์ผœ์ง„ ์›น ์‚ฌ์ดํŠธ๊ฐ€ ๊บผ์ง„๋‹ค.
  • ์›น ์‚ฌ์ดํŠธ๊ฐ€ ๊บผ์ง€๋ฉด ๋Œ€๊ธฐ ์ค‘์ด๋˜ ์›น ์‚ฌ์ดํŠธ๊ฐ€ ์ผœ์ง„๋‹ค.
  • ์›น ์‚ฌ์ดํŠธ๊ฐ€ 5๊ฐœ๊ฐ€ ์ผœ์ง€๋ฉด ์›น ์‚ฌ์ดํŠธ๋Š” ๋Œ€๊ธฐ ์ƒํƒœ์— ๋“ค์–ด๊ฐ„๋‹ค.
  • ์›น ์‚ฌ์ดํŠธ๊ฐ€ 5๊ฐœ ์ดํ•˜๊ฐ€ ์ผœ์ ธ ์žˆ์œผ๋ฉด ๋Œ€๊ธฐ ์ค‘์ด๋˜ ์›น ์‚ฌ์ดํŠธ๊ฐ€ ์ผœ์ง„๋‹ค.

์•„๋ž˜ ์ฝ”๋“œ๋ฅผ ๋ณต์‚ฌํ•ด์„œ ์‹ค์Šตํ•ด ๋ณด์ž.

public class Computer {

    public static void main(String[] args) {
        final WebBrowser webBrowser = new WebBrowser(5);

        final Thread threadA = new Thread(new WebSite("Google", webBrowser));
        final Thread threadB = new Thread(new WebSite("Naver", webBrowser));
        final Thread threadC = new Thread(new WebSite("Daum", webBrowser));
        final Thread closer = new Thread(new WebSiteCloser(webBrowser));

        closer.start();
        threadA.start();
        threadB.start();
        threadC.start();
    }
}

public class WebSite implements Runnable {

    private final String webSiteName;
    private final WebBrowser webBrowser;

    public WebSite(final String webSiteName, final WebBrowser webBrowser) {
        this.webSiteName = webSiteName;
        this.webBrowser = webBrowser;
    }

    @Override
    public void run() {
        synchronized (this) {
            while (true) {
                try {
                    Thread.sleep(new Random().nextInt(1000));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                webBrowser.createNewTab(webSiteName);
            }
        }
    }
}

public class WebBrowser {

    private static final String SPACE = " ";

    private final List<String> webSiteNames = new ArrayList<>();
    private final List<Integer> webSiteIndexes = new ArrayList<>();
    private final int maxWebCount;
    private int webSiteIndex = 0;

    public WebBrowser(final int maxWebCount) {
        this.maxWebCount = maxWebCount;
    }

    public synchronized void createNewTab(final String webSiteName) {
        try {
            if (full()) {
                wait();
            }
            System.out.println(webSiteName + " ์‚ฌ์ดํŠธ๊ฐ€ ์ผœ์ง€๋Š” ์ค‘์ž…๋‹ˆ๋‹ค...");
            Thread.sleep(new Random().nextInt(1000));
            webSiteNames.add(webSiteName);
            webSiteIndexes.add(++webSiteIndex);
            showRunningBrowser();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private void showRunningBrowser() {
        if (webSiteNames.size() > maxWebCount) {
            throw new UnsupportedOperationException("ํ˜„์žฌ ๋ธŒ๋ผ์šฐ์ € ํƒญ์ด 6๊ฐœ ์ด์ƒ ํ™œ์„ฑํ™” ๋˜์–ด ๊ฐ•์ œ ์ข…๋ฃŒํ•ฉ๋‹ˆ๋‹ค...");
        }

        System.out.println("โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”");
        System.out.println("โ”‚ โ—† Wilder Web Browser                                                    - โ–ก x โ”‚");
        System.out.println("โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜");

        StringBuilder browserNameLine = new StringBuilder();
        StringBuilder browserUnderLine = new StringBuilder();

        if (webSiteNames.size() > 0) {
            browserNameLine.append("โ”‚");
            browserUnderLine.append("โ””");
        }

        for (int i = 0; i < webSiteNames.size(); i++) {
            browserNameLine.append(generateWebSiteName(webSiteNames.get(i)))
                .append(generateWebSiteIndex(webSiteIndexes.get(i)))
                .append(" โ”‚");
            browserUnderLine.append("โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜");
        }

        System.out.println(browserNameLine);
        System.out.println(browserUnderLine);
    }

    private String generateWebSiteName(final String name) {
        StringBuilder builder = new StringBuilder();

        if (name.length() > 11) {
            return name.substring(0, 11);
        }

        int space = 11 - name.length();
        int interval = space / 2;

        builder.append(SPACE.repeat(interval))
            .append(name)
            .append(SPACE.repeat(11 - interval - name.length()));

        return builder.toString();
    }

    private String generateWebSiteIndex(final int index) {
        if (index < 10) {
            return "00" + index;
        }
        if (index < 100) {
            return "0" + index;
        }
        return "" + index;
    }

    public boolean isNotEmpty() {
        return webSiteNames.size() != 0;
    }

    public boolean hasSpace() {
        return webSiteNames.size() < maxWebCount;
    }

    public boolean full() {
        return !hasSpace();
    }

    public synchronized void removeAndNotify() {
        if (isNotEmpty()) {
            System.out.println(webSiteNames.get(0) + " ์‚ฌ์ดํŠธ๊ฐ€ ์ข…๋ฃŒ๋ฉ๋‹ˆ๋‹ค.");
            webSiteNames.remove(0);
            webSiteIndexes.remove(0);
            showRunningBrowser();
            notify();
        }
    }
}

public class WebSiteCloser implements Runnable {

    private final WebBrowser webBrowser;

    public WebSiteCloser(WebBrowser webBrowser) {
        this.webBrowser = webBrowser;
    }

    @Override
    public void run() {
        try {
            while (true) {
                Thread.sleep(3000);
                webBrowser.removeAndNotify();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

image

5๊ฐœ๋ฅผ ๋„˜์ง€ ์•Š๋Š” ์„ ์—์„œ ์ƒˆ๋กœ์šด ํƒญ์ด ๋นˆ์ž๋ฆฌ๊ฐ€ ์ƒ๊ธธ ๋•Œ๋งˆ๋‹ค ์ถ”๊ฐ€๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

์ด๋ ‡๊ฒŒ ์กฐ๊ฑด ๋ณ€์ˆ˜๋ฅผ ์ด์šฉํ•˜์—ฌ ๋™๊ธฐํ™”๋ฅผ ํ•ด๋ณด๋Š” ๊ฒฝํ—˜๊นŒ์ง€ ํ•ด๋ดค๋‹ค. ์ ์ ˆํ•œ ์˜ˆ์‹œ๋Š” ์•„๋‹ ์ˆ˜ ์žˆ์ง€๋งŒ, ์ด ๊ธ€์˜ ํ•ต์‹ฌ์€ ์–ด๋–ป๊ฒŒ, ์–ด๋–ค ๋ฐฉ์‹์œผ๋กœ Java ์—์„œ ๋™๊ธฐํ™”๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š”์ง€๋ฅผ ์•Œ์•„๋ณด๋Š” ์‹œ๊ฐ„์ด์—ˆ๋‹ค.

๊ฒฐ๋ก 

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

์ฐธ๊ณ