๐Ÿš• ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด์„ ์•ˆ์ „(Thread-safe)ํ•˜๊ณ  ํŽธํ•˜๊ฒŒ ๋ชจ์‹ญ๋‹ˆ๋‹ค.

Letsdevยท2023๋…„ 10์›” 18์ผ

๐Ÿ”ฎ ํŠน์ง•/๋ชฉ์  4~5 min read
๐Ÿ“œ ์ฝ”๋“œ/๋™์‹œ์„ฑ 8 min read


๐ŸŒŸ ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด์ด๋ž€?

์‹ฑ๊ธ€ํ†ค ํŒจํ„ด์˜ ์ด๋ฆ„์—์„œ ์•Œ ์ˆ˜ ์žˆ๋“ฏ์ด, ์ด ํŒจํ„ด์€ 'ํ•˜๋‚˜Single์˜ย ๋ช…์‚ฌํ™”_{Single์˜\ ๋ช…์‚ฌํ™”}'์™€ ๊ด€๋ จ์ด ๊นŠ์Šต๋‹ˆ๋‹ค.
์ด ํŒจํ„ด์€ ๊ฐ์ฒด๋ฅผ ํ•˜๋‚˜๋งŒ ๋งŒ๋“ค์–ด์„œ ์ด๋ฅผ ์žฌ์‚ฌ์šฉํ•˜๋Š” ํŒจํ„ด์ž…๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๋Š” ์ด ํŒจํ„ด์„ ์„ค๋ช…ํ•˜๋Š” ๊ณผ์ •์—์„œ '์œ ์ผ ๊ฐ์ฒด'๋ฅผ '์‹ฑ๊ธ€ํ†ค'์ด๋ผ ๋ถ€๋ฅผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ๊ทธ๋ฆผ์—์„œ ์‹ฑ๊ธ€ํ†ค์ด๋ผ๋Š” ์‚ฌ๋žŒ์ด ์„œ ์žˆ๊ณ , ๋ˆ„๊ตฐ๊ฐ€ "์•ผ ์™œ ๋งจ๋‚  ๋„ค๊ฐ€ ์™€?"๋ผ๊ณ  ๋ฌผ์–ด๋ณด๊ณ  ์žˆ๋‹ค. ์‹ฑ๊ธ€ํ†ค์€ "์ด ์ง์—…์€ ๋‚˜๋ฐ–์— ์—†์–ด~"๋ผ๊ณ  ๋Œ€๋‹ตํ•˜๊ณ  ์žˆ๋‹ค. ์ „์‚ฐ ์ธ๋ ฅ์ด ํ•œ ๋ช…๋ฟ์ธ ํšŒ์‚ฌ์˜ ํ’๊ฒฝ๊ณผ๋„ ๋‹ฎ์•˜์Šต๋‹ˆ๋‹ค.

๐Ÿ’ก ์™œ ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด์„ ์‚ฌ์šฉํ• ๊นŒ?

(์žฅ) ๊ฐ์ฒด ์ƒ์„ฑ ๋น„์šฉ์˜ ์ ˆ๊ฐ
์‹ฑ๊ธ€ํ†ค ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜๋ฉด, ๊ณณ๊ณณ์—์„œ ๋งค๋ฒˆ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋น„์šฉ์„ ๋“ค์ผ ํ•„์š”๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.
๊ทธ๋Ÿฐ๋ฐ ์ด๊ฑด ์‚ฌ์‹ค ์‹ฑ๊ธ€ํ†ค์ด๋ผ์„œ ์–ป๋Š” ์žฅ์ ์€ ์•„๋‹ˆ๊ณ , ๊ฐ์ฒด๋ฅผ ๋ฏธ๋ฆฌ ๋งŒ๋“ค์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ์–ป๋Š” ์žฅ์ ์ž…๋‹ˆ๋‹ค.

๋’ค๋”ฐ๋ฅด๋Š” ์žฅ์ ์œผ๋กœ ๋กœ์ง ๊ณณ๊ณณ์—์„œ ๊ฐ์ฒด ์ƒ์„ฑ์— ์˜ํ•œ ๋ฉ”๋ชจ๋ฆฌ ๋‚ญ๋น„๋ฅผ ์ค„์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๊ฐ์ฒด ์ƒ์„ฑ ํ›„ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ํ•ด์ œํ•˜๋Š” ๋น„์šฉ์„ ์ ˆ๊ฐ์—๋„ ์˜ํ–ฅ์„ ์ค๋‹ˆ๋‹ค. ์ฆ‰, (๋งค๋ฒˆ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•  ๋•Œ๋ณด๋‹ค) ๋ฉ”๋ชจ๋ฆฌ๋„ ์•„๋ผ๋ฉด์„œ ์กฐ๊ธˆ ๋” ๋น ๋ฅธ ๋™์ž‘์„ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

(์žฅ) ์œ ์ผ ๊ฐ์ฒด์˜ ๋ณด์žฅ๊ณผ ๊ณต์œ 
๊ทธ ์™ธ ์žฅ์ ์œผ๋กœ๋Š” ์œ ์ผ ๊ฐ์ฒด์ด๊ธฐ ๋•Œ๋ฌธ์— ๊ณต์œ ํ•˜๊ธฐ์— ์šฉ์ดํ•œ ๊ฐ์ฒด์ด๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ฐ์ฒด๊ฐ€ ์ € ๊ฐ์ฒด์ธ์ง€ ๊ฑฑ์ •ํ•  ๊ฒƒ ์—†์ด, ์ด ๋ฃจํ‹ด์—์„œ๋„ ์ € ๋ฃจํ‹ด์—์„œ๋„ ๋™์ผํ•œ ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๊ฒ ์ฃ .

(๋‹จ) ์œ ์ผ ๊ฐ์ฒด์˜ ๊ณต์œ 
์ด๋Š” ๋™์‹œ์— ๋‹จ์ ์ด ๋  ์ˆ˜ ์žˆ๋Š”๋ฐ ์ด ๊ฐ์ฒด์˜ ์ž์›์ด ๋ฌด๋ถ„๋ณ„ํ•˜๊ฒŒ ๊ณณ๊ณณ์—์„œ ๋ณ€๊ฒฝ๋  ์—ฌ์ง€๊ฐ€ ์žˆ๋‹ค๋ฉด ์„œ๋กœ ๋‹ค๋ฅธ ๋ฃจํ‹ด์—์„œ ์˜ํ–ฅ์„ ๋ฐ›์„ ์—ฌ์ง€๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ์ด๋Ÿด ๋• ์•Œ๋งž๊ฒŒ ์‚ฌ์šฉํ•˜๋ฉด ํ•ด๊ฒฐ๋ฉ๋‹ˆ๋‹ค(์ž˜๋ชป ์‚ฌ์šฉํ•œ ๊ฒฝ์šฐ๊ฐ€ ๋ฌธ์ œ๋ผ๋Š” ๊ฒƒ).

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

(๋‹จ) ์ƒ์„ฑ ์‹œ ์ง€์—ฐ ๋กœ๋”ฉ ๋ฐ ๋™์‹œ์„ฑ์„ ๋ณด์žฅํ•˜๋Š” ๋ฐ์— ์ฃผ์˜๊ฐ€ ํ•„์š”ํ•จ.
์ถ”๊ฐ€์ ์ธ ๋‹จ์ ์œผ๋กœ๋Š” ์ƒ์„ฑ์— ์žˆ์–ด์„œ ์ฃผ์˜๊ฐ€ ํ•„์š”ํ•˜๋‹ค๋Š” ์  ์ •๋„์ธ๋ฐ, ์˜ค๋Š˜ ์ด ๊ธ€์—์„  ์ด ๋ฌธ์ œ๋ฅผ ์ž๋ฐ”์—์„œ ์–ด๋–ป๊ฒŒ ํ•ด๊ฒฐํ•˜๋ฉด ๋˜๋Š”์ง€ ๋‹ค๋ฃน๋‹ˆ๋‹ค.

PS. ์Šคํ”„๋ง์—์„œ๋Š” โœ๏ธ

๋งŒ์•ฝ ์šฐ๋ฆฌ๊ฐ€ ์Šคํ”„๋ง์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋‹ค๋ฉด, ์Šคํ”„๋ง์˜ ์ฃผ์š” ์ปจํ…Œ์ด๋„ˆ(IoC ์ปจํ…Œ์ด๋„ˆ)๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ์šฐ๋ฆฌ๊ฐ€ ์‚ฌ์šฉํ•  ์˜์กด์„ฑ ๊ฐ์ฒด Bean๋“ค์„ ์‹ฑ๊ธ€ํ†ค ๊ฐ์ฒด๋กœ ์ทจ๊ธ‰ํ•ฉ๋‹ˆ๋‹ค.

๋ฌผ๋ก  ์šฐ๋ฆฌ๊ฐ€ ์ด ํด๋ž˜์Šค๋ฅผ ์ž‘์„ฑํ•  ๋•Œ ์ƒ์„ฑ์ž๋ฅผ ์ง์ ‘์ ์œผ๋กœ ๋ง‰์€ ๊ฒƒ์€ ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์—, ์ถ”๊ฐ€์ ์œผ๋กœ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•ด์„œ ๋กœ์ง์— ์‚ฌ์šฉํ•  ์ˆœ ์žˆ์Šต๋‹ˆ๋‹ค๋งŒ, ์ด ๊ฒฝ์šฐ ์Šคํ”„๋ง์ด ์ด ๊ฐ์ฒด๋ฅผ ์ž๋™์œผ๋กœ Bean์œผ๋กœ ์ทจ๊ธ‰ํ•˜์ง„ ์•Š์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

(์ƒ์„ฑ์ž๋ฅผ ๋ง‰์€ ๊ฒƒ์€ ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์— ์˜จ์ „ํžˆ ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด์„ ์ ์šฉํ•œ ๊ฒƒ์€ ์•„๋‹ˆ๊ณ , ์‹ฑ๊ธ€ํ†ค ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์ƒ์„ฑํ•ด ์ทจ๊ธ‰ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.)

์™œ ๋ชจ๋“  ๊ฒƒ์„ static์œผ๋กœ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ์‹ฑ๊ธ€ํ†ค ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค์–ด์„œ ์“ธ๊นŒ?

๊ทธ๋Ÿฐ๋ฐ ๊ฐ์ฒด๋ฅผ ํ•˜๋‚˜๋งŒ ๋งŒ๋“ค์–ด์„œ ๊ทธ ๊ฐ์ฒด๋ฅผ ํ†ตํ•ด ํด๋ž˜์Šค์˜ ์˜จ๊ฐ– ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•œ๋‹ค๋Š” ์„ค๋ช…์—์„œ ํ•œ ๊ฐ€์ง€ ์˜๋ฌธ์„ ์ƒ๊ฐํ•ด ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ํด๋ž˜์Šค์˜ ๋ชจ๋“  ๋ฉค๋ฒ„ ๋ณ€์ˆ˜์™€ ๋ฉ”์„œ๋“œ๋ฅผ static์œผ๋กœ ์ทจ๊ธ‰ํ•˜๋ฉด ๋™์ผํ•œ ๊ฒƒ ์•„๋‹๊นŒ?

์ด๋Ÿฌํ•œ ์˜๋ฌธ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿผ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  static์„ ์‚ผ๊ฐ€๋Š” ๊ฒƒ์€ static์˜ ์—ฌ๋Ÿฌ ์•ฝ์  ๋•Œ๋ฌธ์ด์ฃ .

static์€ ์–ธ์ œ ์–ด๋””์—์„œ ์–ด๋–ป๊ฒŒ ๋ณ€๊ฒฝ๋ ์ง€ ๋ชจ๋ฅด๋Š”(final์ด ์•„๋‹ˆ๋ผ๋ฉด) ๋ฐ์ดํ„ฐ๊ฐ€ ๋จ๊ณผ ๋™์‹œ์— ์ƒ๋ช…์ฃผ๊ธฐ๊ฐ€ ์˜๋„์— ๋น„ํ•ด ๊ธธ ์ˆ˜๋ฐ–์— ์—†์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ํŠน์„ฑ์€ ์ปดํŒŒ์ผ๋Ÿฌ์˜ ์ตœ์ ํ™” ์ „๋žต์—๋„ ํ˜ผ๋ž€์„ ์‹ฌ์–ด์ค„ ์ˆ˜ ์žˆ์ฃ . ๋”ฐ๋ผ์„œ static์€ static final์„ ์‚ฌ์šฉํ•  ๋•Œ๋ฅผ ์ œ์™ธํ•˜๋ฉด ์ผ๋ฐ˜์ ์œผ๋กœ ๊ผญ ํ•„์š”ํ•œ ํŒจํ„ด์ด ์•„๋‹ ๋• ์‚ผ๊ฐ€๋Š” ๊ฒƒ์ด ์ข‹์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

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


์‹ฑ๊ธ€ํ†ค ํŒจํ„ด ๋ ˆ์‹œํ”ผ

๊ฐœ๋…์„ ์„ค๋ช…ํ•˜๊ธฐ ์œ„ํ•œ ๊ฐ„๋‹จํ•œ ๊ตฌํ˜„ ๐Ÿฐ

์‹ฑ๊ธ€ํ†ค ํŒจํ„ด์˜ ๊ธฐ๋ณธ์ ์ธ ์„ค๋ช…์„ ์œ„ํ•œ ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.

  • ๋‹ค๋ฅธ ๊ณณ์—์„œ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์—†๋„๋ก ์ƒ์„ฑ์ž์˜ ๊ณต๊ฐœ ๋ฒ”์œ„๋ฅผ ์ขํž™๋‹ˆ๋‹ค.
  • ์‹ฑ๊ธ€ํ†ค ๊ฐ์ฒด๋ฅผ ํด๋ž˜์Šค ๋‚ด๋ถ€์— ํ•˜๋‚˜ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค(static).
  • ์‹ฑ๊ธ€ํ†ค ๊ฐ์ฒด๋ฅผ ์ œ๊ณตํ•˜๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ํ•˜๋‚˜ ๋‘ก๋‹ˆ๋‹ค(static).

๊ทธ๋Ÿฌ๋ฉด ์ด ๊ฐ์ฒด๋Š” ์ด ํด๋ž˜์Šค์— ์žˆ๋Š” ์—ฌ๋Ÿฌ ์†์„ฑ๊ณผ ๊ธฐ๋Šฅ์„ non-static์œผ๋กœ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

public class MyExample {
    // [1] ์‹ฑ๊ธ€ํ†ค ๊ฐ์ฒด๋ฅผ ์—ฌ๊ธฐ์—์„œ ํ•˜๋‚˜ ๋งŒ๋“ญ๋‹ˆ๋‹ค.
    private static final MyExample INSTANCE = new MyExample();
    
    // [2] (ํ•ต์‹ฌ) ๋‹ค๋ฅธ ๊ณณ์—์„œ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์—†๋„๋ก private ์ƒ์„ฑ์ž!
    private MyExample() {}

    // [3] ์ธ์Šคํ„ด์Šค๋ฅผ ์ œ๊ณตํ•˜๋Š” ์ •์ (static) ๋ฉ”์„œ๋“œ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.
    public static MyExample getInstance() {
        return INSTANCE;
    }
    
    // (์ด์ œ ๋‹ค๋ฅธ ๊ธฐ๋Šฅ์„ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.)
}

๊ทธ๋Ÿฌ๋‚˜ ์ด ๋ฐฉ์‹์€ ํด๋ž˜์Šค๋งŒ ์‚ฌ์šฉํ•˜๋Š” ์‹œ์ ์—๋„ ์ธ์Šคํ„ด์Šค๋ฅผ ์ดˆ๊ธฐํ™”ํ•ด ๋ฉ”๋ชจ๋ฆฌ์— ์˜ฌ๋ฆฌ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
์ž๋ฐ”๋Š” ํด๋ž˜์Šค๋ฅผ ๋Ÿฐํƒ€์ž„ ๋ฉ”๋ชจ๋ฆฌ์— ์˜ฌ๋ฆด ๋•Œ(= ํด๋ž˜์Šค ๋กœ๋“œ ํƒ€์ž„), ๊ทธ ํด๋ž˜์Šค์˜ static ํ•„๋“œ๋„ ์ดˆ๊ธฐํ™”ํ•ด์„œ ๋ฉ”๋ชจ๋ฆฌ์— ์˜ฌ๋ฆฌ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๋Š” '์ด ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์‹œ์ '์— ๋ฉ”๋ชจ๋ฆฌ์— ์˜ฌ๋ฆฌ๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค.

โฑ ์ง€์—ฐ ๋กœ๋”ฉ

๊ทธ๋ž˜์„œ ์šฐ๋ฆฌ๋Š” ์ง€์—ฐ๋กœ๋”ฉ์„ ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.
๋‹ค์Œ ์ฝ”๋“œ๋Š” ์ด ๊ฐ์ฒด๋ฅผ ์‹ค์ œ ์‚ฌ์šฉํ•˜๋Š” ์‹œ์ ์— ๊ฐ์ฒด ์ƒ์„ฑ์„ ์ˆ˜ํ–‰ํ•˜๋„๋ก ๋ณ€๊ฒฝํ•ฉ๋‹ˆ๋‹ค.

public class MyExample {
    // [1] ์‹ฑ๊ธ€ํ†ค ๊ฐ์ฒด๋ฅผ ์•„์ง ์•ˆ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ์ด๋•Œ null๋กœ ์ดˆ๊ธฐํ™”๋˜๋Š” ์ž๋ฐ” ํŠน์ง•์ด ์žˆ์Šต๋‹ˆ๋‹ค.
    private static MyExample INSTANCE; // (final์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.)
    
    private MyExample() {}

    public static MyExample getInstance() {
        // [2] null์ธ ๊ฒฝ์šฐ์—๋งŒ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•ด์„œ ๋‹ด์Šต๋‹ˆ๋‹ค.
        if (INSTANCE == null) {
            INSTANCE = new MyExample(); // ์ด์ œ INSTANCE๋Š” null์ด ์•„๋‹™๋‹ˆ๋‹ค.
        }
        
        // ๊ฐ์ฒด๋ฅผ ๋ฏฟ๊ณ  ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜๊ฒ ์ฃ . ์•„๋งˆ๋„์š”?
        return INSTANCE;
    }
}

๐ŸŽพ + ๐ŸŽพ ์‹ฑ๊ธ€ํ†ค ์ƒ์„ฑ์˜ ๋™์‹œ์„ฑ ๋ฌธ์ œ

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

์‚ฌ์šฉ์ž์˜ ๊ฐ ์š”์ฒญ์€ ๊ฐ๊ฐ์˜ ์Šค๋ ˆ๋“œ์—์„œ ์ฒ˜๋ฆฌ๋œ๋‹ค๋Š” ๊ฒƒ์„ ์ƒ๊ฐํ•˜๋ฉฐ ๋‹ค์Œ ํ๋ฆ„์„ ์‚ดํŽด๋ด…์‹œ๋‹ค.

โฌ‡๏ธ ๋‘˜ ์ด์ƒ์˜ ์Šค๋ ˆ๋“œ๊ฐ€ ๋น„์–ด ์žˆ๋Š” ์‹ฑ๊ธ€ํ†ค ์ž๋ฆฌ๋ฅผ ๋ฐœ๊ฒฌํ•ฉ๋‹ˆ๋‹ค.

โฌ‡๏ธ ๋‘˜ ์ด์ƒ์˜ ์Šค๋ ˆ๋“œ๊ฐ€ ์‹ฑ๊ธ€ํ†ค ๊ฐ์ฒด๋ฅผ ๊ฐ์ž ์ƒ์„ฑํ•˜์—ฌ ์‚ฌ์šฉํ•˜์˜€์Šต๋‹ˆ๋‹ค.

โฌ† ์ด ๊ณผ์ •์—์„œ ์ด๋ฏธ ๋” ์ด์ƒ '์‹ฑ๊ธ€ํ†ค'์ด ์•„๋‹Œ ๊ฐ์ฒด๊ฐ€ ํ•˜๋‚˜๋Š” ์กด์žฌํ–ˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ด๊ฒƒ์ด ์‹ฑ๊ธ€ํ†ค ๊ฐ์ฒด ๋“ฑ์„ ์ƒ์„ฑํ•  ๋•Œ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” '๋™์‹œ์„ฑ ๋ฌธ์ œ'{}์ž…๋‹ˆ๋‹ค.
๋‹คํ–‰ํžˆ ์ž๋ฐ”์—์„œ๋Š” ์ด๋Ÿฐ ๋ฌธ์ œ๋ฅผ ๋Œ€์ฒ˜ํ•  ์ˆ˜ ์žˆ๋Š” ์—ฌ๋Ÿฌ ์ˆ˜๋‹จ์ด ์žˆ๋Š”๋ฐ, ์•„๋ž˜ ์ฝ”๋“œ์—์„œ ์„ค๋ช…ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

์Šค๋ ˆ๋“œ ์„ธ์ดํ”„ (1): synchronized method

์•„์ฃผ ๋ฌด์‹ํ•œ ํ•ด๊ฒฐ ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค.
๊ทธ๋ƒฅ ๊ฐ์ฒด๋ฅผ ๋ฐ›๋Š” ํ–‰์œ„ ์ž์ฒด๋ฅผ ์Šค๋ ˆ๋“œ๋“ค์ด ํ•œ ์Šค๋ ˆ๋“œ์”ฉ ์ค„์„ ์„œ์„œ ์ฒœ์ฒœํžˆ ๋ฐ›์•„๊ฐ€๊ฒŒ ํ•˜๋Š” ๊ฒ๋‹ˆ๋‹ค.

public class MyExample {
    private static MyExample INSTANCE;
    
    private MyExample() {}

    // synchronized ์ˆ˜์‹์–ด๋ฅผ ํ†ตํ•ด, ์ด ๋ฉ”์„œ๋“œ๋Š” ๋™์‹œ์— ํ•˜๋‚˜์˜ ์Šค๋ ˆ๋“œ๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    public static synchronized MyExample getInstance() {
        if (INSTANCE == null) {
            // ์—ฌ๊ธฐ์— ๋‘˜ ์ด์ƒ์˜ ์Šค๋ ˆ๋“œ๊ฐ€ ๋“ค์–ด์˜ฌ ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— ํ•˜๋‚˜์˜ ๊ฐ์ฒด์ž„์„ ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค.
            INSTANCE = new MyExample();
        }
        
        // ์ด๋ฒˆ์—” ์ •๋ง๋กœ ๊ฐ์ฒด๋ฅผ ๋ฏฟ๊ณ  ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
        return INSTANCE;
    }
}

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

์Šค๋ ˆ๋“œ ์„ธ์ดํ”„ (2): double-checked synchronized

์ ์–ด๋„ ์œ„์™€ ๊ฐ™์€ ๋ฌธ์ œ๋ฅผ ๋ง‰๊ธฐ ์œ„ํ•ด์„œ๋Š” ์–ด๋–กํ• ๊นŒ์š”?
์ด๋ฏธ INSTANCE๊ฐ€ ์‹ฑ๊ธ€ํ†ค ๊ฐ์ฒด๋กœ ์ดˆ๊ธฐํ™”๋˜์–ด ์žˆ์„ ๋•Œ๋Š” ์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ์˜ ๋™์‹œ ์ ‘์†์„ ํ—ˆ๋ฝํ•ด๋„ ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

public class MyExample {
    private static MyExample INSTANCE;
    
    private MyExample() {}

    public static MyExample getInstance() {
        if (INSTANCE == null) {
            // [A] ์—ฌ๊ธฐ๊นŒ์ง„ ์•„๊นŒ์ฒ˜๋Ÿผ ๋™์‹œ์— ๋‘˜ ์ด์ƒ์˜ ์Šค๋ ˆ๋“œ๊ฐ€ ๋“ค์–ด์˜ฌ ๋•Œ๋„ ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
            synchronized (INSTANCE) { // ์ด ์ž์›์— ๋Œ€ํ•ด์„œ ์ˆœ์ฐจ์ ์œผ๋กœ ์ ‘๊ทผํ•˜๊ฒŒ ํ•˜๊ณ 
                // ๊ทธ๋Ÿผ์—๋„ [A] ๊ตฌ๊ฐ„์—์„œ ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ๊ฐ€ ๊ธฐ๋‹ค๋ฆฌ๊ณ  ์žˆ์„ ์ˆ˜ ์žˆ์œผ๋‹ˆ๊นŒ
                if (INSTANCE == null) { // ์—ฌ๊ธฐ์„œ ํ•œ ๋ฒˆ ๋” ์ฒดํฌํ•ด์„œ
                    INSTANCE = new MyExample(); // ์ง„์งœ ์œ ์ผํ•œ ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค.
                }
            }
        }
        // ์œ„ if๋ฌธ ๋ธ”๋Ÿญ์€ INSTANCE๊ฐ€ `null`์ด ์•„๋‹ ๋•Œ,
        // `synchronized () {...}` ๋ธ”๋Ÿญ์„ ์ƒ๋žตํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.
        
        // ๊ฐ์ฒด๋ฅผ ๋ฏฟ๊ณ  ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ๊ทธ๊ฒƒ๋„ ๋™์‹œ์— ์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ๊ฐ€ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ณ ์š”.
        return INSTANCE;
    }
}
  • ๋ฐ”๊นฅ์ชฝ if๋ฌธ: ์ด๋ฏธ ๊ฐ์ฒด๊ฐ€ ์ƒ์„ฑ๋˜์–ด ์žˆ๋‹ค๋ฉด, ๋” ์ด์ƒ synchronized ๋ธ”๋Ÿญ์— ์ง„์ž…ํ•  ํ•„์š”๊ฐ€ ์—†๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ๊ฐ€ ๋™์‹œ์— ์ด ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.

  • ์•ˆ์ชฝ if๋ฌธ: ๋ฐ”๊นฅ์ชฝ if๋ฌธ์€ ๋™์‹œ์„ฑ์„ ๋ณด์žฅํ•˜๊ธฐ ์œ„ํ•œ ๊ฒƒ์ด ์•„๋‹ˆ์—ˆ์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์•ˆ์ชฝ if๋ฌธ ์ž…๊ตฌ์—๋Š” ๋™์‹œ์— ๋ฐ”๊นฅ์ชฝ if๋ฌธ์„ ํ†ต๊ณผํ–ˆ๋˜ ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ๊ฐ€ ๋‹ค์Œ ์ฐจ๋ก€์— ๋‹ค๊ฐ€์˜ฌ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์ฆ‰ ๋‘˜ ์ด์ƒ์˜ ์Šค๋ ˆ๋“œ๊ฐ€ synchronized ๋ธ”๋Ÿญ์— ์ฐจ๋ก€๋กœ ํ•˜๋‚˜์”ฉ ์ง„์ž…ํ•  ์ˆœ ์žˆ์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๋จผ์ € ๋ฐฉ๋ฌธํ•œ ์Šค๋ ˆ๋“œ๊ฐ€ ์ด๋ฏธ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ–ˆ์„ ๋•Œ ๋‹ค์Œ์— ์˜จ ์Šค๋ ˆ๋“œ๋Š” ๊ฐ์ฒด๋ฅผ ์ƒˆ๋กœ ์ƒ์„ฑํ•  ์ˆ˜ ์—†๋„๋ก ์•ˆ์ชฝ if๋ฌธ์œผ๋กœ ๋ง‰์•„ ๋‘” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์Šค๋ ˆ๋“œ ์„ธ์ดํ”„ (3): ํด๋ž˜์Šค ๋กœ๋“œ ํƒ€์ž„

์šฐ๋ฆฌ๊ฐ€ ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด์„ ์ฒ˜์Œ ์„ค๋ช…ํ•  ๋•Œ ์œ„์—์„œ ๋ดค๋˜ ์ฝ”๋“œ๋ฅผ ๊ธฐ์–ตํ•˜์‹œ๋‚˜์š”?
๊ทธ ์ฝ”๋“œ๊ฐ€ ๋น„๋ก '์ง€์—ฐ ๋กœ๋”ฉ'์ด๋ผ๋Š” ์ด์ ์€ ์—†๋”๋ผ๋„, ์ด๋ฏธ '์Šค๋ ˆ๋“œ ์„ธ์ดํ”„'๋ฅผ ๋ณด์žฅํ•˜๊ณ ๋Š” ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๊ฒƒ์„ ์ œ๊ฐ€ ์–ด๋–ป๊ฒŒ ์•Œ๊นŒ์š”?
์‚ฌ์‹ค ๊ทธ๋ƒฅ, ์ž๋ฐ”๊ฐ€ ๊ทธ๋ ‡๊ฒŒ ์„ค๋ช…ํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

์ž๋ฐ”๋Š” ํด๋ž˜์Šค๋ฅผ ๋ฉ”๋ชจ๋ฆฌ์— ์˜ฌ๋ฆฌ๋Š” 'ํด๋ž˜์Šค ๋กœ๋“œ ํƒ€์ž„'์—๋Š” ๋™์‹œ์„ฑ์„ ๋ณด์žฅํ•ด ์ค๋‹ˆ๋‹ค.
์ฆ‰, ์šฐ๋ฆฌ๊ฐ€ ๋„ˆ๋ฌด ๊ณ ์ƒํ•  ํ•„์š” ์—†์ด ์ด 'ํด๋ž˜์Šค ๋กœ๋“œ ํƒ€์ž„'์„ ์ด์šฉํ•˜๋ฉด ๋˜๋Š” ๊ฒ๋‹ˆ๋‹ค.

๊ทธ๋Ÿฐ๋ฐ ์šฐ๋ฆฌ๊ฐ€ ์›ํ•˜๋Š” ๊ฒƒ์€ '์ง€์—ฐ(lazy) ๋กœ๋”ฉ'๊ณผ '์Šค๋ ˆ๋“œ ์„ธ์ดํ”„(thread-safe)' ๋ชจ๋‘์ž…๋‹ˆ๋‹ค.
๋”ฐ๋ผ์„œ '์ธ์Šคํ„ด์Šค๊ฐ€ ์ฒ˜์Œ ์‚ฌ์šฉ๋  ๋•Œ ๋ฉ”๋ชจ๋ฆฌ์— ์ฒ˜์Œ ๋กœ๋“œ๋˜๋Š” ํด๋ž˜์Šค'๊ฐ€ ์žˆ๋‹ค๋ฉด ์•„๋ฌด ๊ฑฑ์ • ์—†์—ˆ์„ ๊ฒƒ์ด๋ž€ ๋ง์ด์ฃ .

// ์ฝ”๋“œ๋Š” ๊ด€๋ก€๋ฅผ ๋ฌด์‹œํ•˜๊ณ  ์„ค๋ช… ์ˆœ์„œ์— ๋งž์ถ”์—ˆ์Šต๋‹ˆ๋‹ค.
public class MyExample {
    // [1] ์ด์ œ ์ธ์Šคํ„ด์Šค๋Š” ์—ฌ๊ธฐ ์—†์Šต๋‹ˆ๋‹ค.
    
    // [2] ๊ทธ๋ƒฅ ์ƒ์„ฑ์ž๋‚˜ ๋ง‰์•„ ๋‘ก์‹œ๋‹ค. (์–˜๋Š” ํ•ญ์ƒ ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด์˜ ํ•ต์‹ฌ์ž…๋‹ˆ๋‹ค.)
    private MyExample() {}

    // [3] ๋‚ด๋ถ€ ํด๋ž˜์Šค๋Š” ์œ„ private ์ƒ์„ฑ์ž๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    private static class Holder {
        // ์ด์ œ ์ด๊ณณ์— ์ธ์Šคํ„ด์Šค๋ฅผ ์ž‘์„ฑํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.
        private static final MyExample INSTANCE = new MyExample();
    }
    
    // [4] ๊ทธ๋ž˜๋„ ๋ชฉ์ ์ด ๋˜๋Š” ํƒ‘๋ ˆ๋ฒจ ํด๋ž˜์Šค๊ฐ€ ์ธ์Šคํ„ด์Šค๋ฅผ ์ œ๊ณตํ•˜๊ธด ํ•ด์•ผ ํ•˜์ฃ .
    public static MyExample getInstance() {
        // Holder ํด๋ž˜์Šค๋Š” ์ด๋ ‡๊ฒŒ ์ธ์Šคํ„ด์Šค๋ฅผ ์ œ๊ณตํ•  ๋•Œ ๋ง๊ณค ์•ˆ ์“ฐ์ด๋‹ˆ๊นŒ,
        // ์•„๋ž˜ ์ฝ”๋“œ์— ์˜ํ•ด์„œ (์ฒ˜์Œ ์‚ฌ์šฉ๋  ๋•Œ) ๋ฉ”๋ชจ๋ฆฌ์— ์˜ฌ๋ผ๊ฐ‘๋‹ˆ๋‹ค.
        return Holder.INSTANCE; // ์ด๋•Œ ๋ง๊ณค ๋ฏธ๋ฆฌ ์ƒ์„ฑ๋  ์ผ ์—†๋Š” ๊ฑฐ์ฃ .
    }
}

๐Ÿ›น ๋ฉ”๋ชจ๋ฆฌ์— ์˜ฌ๋ผ๊ฐ€๋Š” ์‹œ์ 

  • INSTANCE๋Š” Holder๋ผ๋Š” ํด๋ž˜์Šค๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ์— ์˜ฌ๋ผ๊ฐˆ ๋•Œ ์ดˆ๊ธฐํ™”๋ฉ๋‹ˆ๋‹ค.
  • ๊ทธ๋ฆฌ๊ณ  Holder๋ผ๋Š” ํด๋ž˜์Šค๋Š” getInstance()๋ผ๋Š” ๋ฉ”์„œ๋“œ๊ฐ€ ์ฒ˜์Œ ํ˜ธ์ถœ๋  ๋•Œ ๋ฉ”๋ชจ๋ฆฌ์— ์˜ฌ๋ผ๊ฐ‘๋‹ˆ๋‹ค.

๊ทธ๊ฒƒ์ด ์ž๋ฐ”์˜ ํŠน์ง•์ด๊ฑฐ๋“ ์š”. ๋งŽ์ด๋“ค ํด๋ž˜์Šค๊ฐ€ import ๋  ๋•Œ ๋ฉ”๋ชจ๋ฆฌ์— ์˜ฌ๋ผ๊ฐ„๋‹ค๊ณ  ์˜คํ•ดํ•˜๋Š”๋ฐ, ์‹ค์ œ๋กœ๋Š” ์‹ค์งˆ์ ์œผ๋กœ ์ฒ˜์Œ ์‚ฌ์šฉํ•  ๋•Œ ๋ฉ”๋ชจ๋ฆฌ์— ์˜ฌ๋ผ๊ฐ‘๋‹ˆ๋‹ค.

์ด๋กœ์จ ์ด Holder๋ผ๋Š” ๋‚ด๋ถ€ ํด๋ž˜์Šค๊ฐ€ ๋‹ค์Œ ๋‘ ํŠน์„ฑ์„ ๋ชจ๋‘ ๋ณด์žฅํ•ด ์ค๋‹ˆ๋‹ค. ๊ทธ๋ƒฅ ์ž์‹ ์ด ํด๋ž˜์Šค๋ผ๋Š” ์ด์œ ๋งŒ์œผ๋กœ์š”. ๊ทธ๊ฒƒ์ด ์ž๋ฐ”์ด๋‹ˆ๊นŒ.

  • Lazy
  • Thread-safe

Holder๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ์— ์˜ฌ๋ผ๊ฐ€๋ฉด์„œ INSTANCE๋ฅผ ์ƒ์„ฑํ•˜๋‹ˆ๊นŒ.


๐Ÿš• ๊ฒฐ๋ก 

๋งˆ์ง€๋ง‰ ๊ฑฐ ์“ฐ์„ธ์š”. ๐Ÿš• ๐Ÿš• ๐Ÿš• ~

  • ์ˆœ์„œ ์ •๋ฆฌํ•œ ์ฝ”๋“œ:

    public class MyExample {
    
        // [1] ์ƒ์„ฑ์ž private
        private MyExample() {}
    
        public static MyExample getInstance() {
            // [2] ๊ฐ์ฒด ์ œ๊ณต(๋‚ด๋ถ€ ํด๋ž˜์Šค ๊ฑฐ)
            return Holder.INSTANCE;
        }
    
        // [3] ์‹ฑ๊ธ€ํ†ค ๊ฐ์ฒด ๋‹ด๋Š” ํด๋ž˜์Šค (ํด๋ž˜์Šค ๋กœ๋“œ ํƒ€์ž„ ํ™œ์šฉ)
        private static class Holder {
            private static final MyExample INSTANCE = new MyExample();
        }
    }
profile
์•„ ์„ฑ์žฅํŒ ์‘ค์…” | ๋ธ”๋กœ๊ทธ ์˜ฎ๊ฒผ์Šต๋‹ˆ๋‹ค: https://blog.letsdev.me (hash node)

1๊ฐœ์˜ ๋Œ“๊ธ€

comment-user-thumbnail
2023๋…„ 10์›” 19์ผ

๋”ฐ๋ด‰

๋‹ต๊ธ€ ๋‹ฌ๊ธฐ