Post

๐ŸŽจ 05. ์‹ฑ๊ธ€ํ„ด ํŒจํ„ด

๐ŸŽจ 05. ์‹ฑ๊ธ€ํ„ด ํŒจํ„ด

๐Ÿซย ํ•˜๋‚˜๋ฟ์ธ ํŠน๋ณ„ํ•œ ๊ฐ์ฒด ๋งŒ๋“ค๊ธฐ, ์‹ฑ๊ธ€ํ„ด ํŒจํ„ด

๊ณ ์ž‘ ๊ฐ์ฒด ์ธ์Šคํ„ด์Šค 1๊ฐœ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•์„ 1๊ฐœ ์žฅ์— ๊ฑธ์ณ์„œ ๋ฐฐ์šด๋‹ค๊ณ ์š”?

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

โ€œ์–ด๋–ป๊ฒŒ ํ•˜๋ฉด ํ•œ ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ๋‘ ๊ฐœ ์ด์ƒ ๋งŒ๋“ค์ง€ ์•Š๊ฒŒ ํ•˜์ง€?โ€

๐Ÿซย ๊ณ ์ „์ ์ธ ์‹ฑ๊ธ€ํ„ด ํŒจํ„ด ๊ตฌํ˜„๋ฒ•

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Singleton {
    // ๊ณ ์ •๋œ ๋‹จ ํ•˜๋‚˜์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์ €์žฅํ•˜๋Š” ์ •์  ๋ณ€์ˆ˜
    private static Singleton uniqueInstance = null;

    // ์™ธ๋ถ€์—์„œ new Singleton() ํ•˜์ง€ ๋ชปํ•˜๋„๋ก ์ƒ์„ฑ์ž๋ฅผ private์œผ๋กœ ์„ ์–ธ
    private Singleton() {
        // ์ƒ์„ฑ์ž ๋‚ด๋ถ€ ๋กœ์ง
    }

    // ์™ธ๋ถ€์—์„œ ์ธ์Šคํ„ด์Šค๋ฅผ ๊ฐ€์ ธ๊ฐ€๋Š” ์œ ์ผํ•œ ๋ฐฉ๋ฒ•
    public static Singleton getInstance() {
        if (uniqueInstance == null) {
            uniqueInstance = new Singleton();
        }
        return uniqueInstance;
    }

    // ๊ธฐํƒ€ ๋ฉ”์†Œ๋“œ
}
๋ผ์ธ์„ค๋ช…
private static uniqueInstance์ด ํด๋ž˜์Šค์˜ ์œ ์ผํ•œ ์ธ์Šคํ„ด์Šค๋ฅผ ์ €์žฅํ•˜๋Š” ์ •์  ๋ณ€์ˆ˜. null๋กœ ์ดˆ๊ธฐํ™”ํ•ด์„œ ์•„์ง ์ƒ์„ฑ๋˜์ง€ ์•Š์•˜์Œ์„ ๋‚˜ํƒ€๋ƒ„.
private Singleton()์ƒ์„ฑ์ž๋ฅผ private์œผ๋กœ ์„ ์–ธํ•ด์„œ ์™ธ๋ถ€์—์„œ new Singleton()์„ ํ•˜์ง€ ๋ชปํ•˜๊ฒŒ ํ•จ. ์˜ค์ง ํด๋ž˜์Šค ๋‚ด๋ถ€์—์„œ๋งŒ ์ƒ์„ฑ ๊ฐ€๋Šฅ.
static getInstance()์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๊ฑฐ๋‚˜ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ฉ”์„œ๋“œ. ์ธ์Šคํ„ด์Šค๊ฐ€ ์—†์œผ๋ฉด ์ƒˆ๋กœ ๋งŒ๋“ค๊ณ , ์žˆ์œผ๋ฉด ๊ธฐ์กด ๊ฒƒ์„ ๋ฐ˜ํ™˜.

ํ•ต์‹ฌ ์š”์•ฝ:

  • ์™ธ๋ถ€์—์„œ ์ง์ ‘ ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์—†๊ฒŒ ํ•˜๊ณ 
  • ๋‚ด๋ถ€์—์„œ ๋‹จ ํ•œ ๋ฒˆ๋งŒ ์ƒ์„ฑ๋˜๋„๋ก ์ œํ•œ
  • ์–ธ์ œ๋“  ๋™์ผํ•œ ๊ฐ์ฒด์— ์ ‘๊ทผ ๊ฐ€๋Šฅํ•˜๋„๋ก static ๋ฉ”์„œ๋“œ๋กœ ๋…ธ์ถœ

๐ŸŽค ํŒจํ„ด ์ง‘์ค‘ ์ธํ„ฐ๋ทฐ - ์‹ฑ๊ธ€ํ„ด ๊ฐ์ฒด์˜ ์‹ฌ๊ฒฝ ๊ณ ๋ฐฑ

์ธํ„ฐ๋ทฐ ์š”์•ฝ:

  • ๋‚˜๋Š” ํ”„๋กœ๊ทธ๋žจ์—์„œ ๋‹จ ํ•˜๋‚˜๋ฟ์ธ ๊ฐ์ฒด๋‹ค
    • ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ ์„ค์ •์ด ๋‹ด๊ฒจ ์žˆ๋Š” ๊ฐ์ฒด๊ฐ€ ์—ฌ๋Ÿฌ ๊ฐœ ์žˆ๋‹ค๋ฉด ์„œ๋กœ ๋‹ค๋ฅธ ์„ค์ • ๋‚ด์—ญ๋„ ์—ฌ๋Ÿฌ ๊ฐœ ์žˆ๋‹ค๋Š” ๋ง์ด ๋œ๋‹ค. ํ•˜์ง€๋งŒ ์‹ฑ๊ธ€ํ„ด์„ ์‚ฌ์šฉํ•˜๋ฉด ํ•œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ๋“ค์–ด์žˆ๋Š” ์–ด๋–ค ๊ฐ์ฒด์—์„œ๋„ ๊ฐ™์€ ์ž์›์„ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ๋‚˜๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด ์ƒ์„ฑ์ž๋ฅผ private์œผ๋กœ ์ˆจ๊ฒผ์Œ
    • public์œผ๋กœ ์ง€์ •๋œ ์ƒ์„ฑ์ž๊ฐ€ ์—†๋‹ค = ์™ธ๋ถ€์—์„œ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์—†๋„๋ก private ์ƒ์„ฑ์ž๋งŒ ์กด์žฌํ•œ๋‹ค.
  • ๋‹จ ํ•˜๋‚˜์˜ ์ธ์Šคํ„ด์Šค๋งŒ ๊ฐ€์ง€๋„๋ก ์ฒ ์ €ํžˆ ํ†ต์ œ๋˜์–ด ์žˆ์Œ
    • ํด๋ž˜์Šค๊ฐ€ ์ธ์Šคํ„ด์Šค๋ฅผ ์˜ค์ง ํ•˜๋‚˜๋งŒ ์ƒ์„ฑํ•˜๊ฒŒ ๋งŒ๋“ค๊ณ , ๋‹ค๋ฅธ ๊ฒฝ๋กœ๋กœ๋Š” ์ ˆ๋Œ€๋กœ ์ƒˆ ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์—†๋„๋ก ๊ฐ•์ œํ•œ๋‹ค.
    • ์‹ฑ๊ธ€ํ„ด ๊ฐ์ฒด๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ new Singleton() ๊ฐ™์€ ๋ฐฉ์‹์œผ๋กœ ์ƒˆ๋กœ์šด ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค์ง€ ๋ชปํ•˜๊ฒŒ ํ•˜๊ณ , getInstance()๋ผ๋Š” ์ •์  ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.

๐Ÿซย ์ดˆ์ฝœ๋ฆฟ ๋ณด์ผ๋Ÿฌ ์ฝ”๋“œ ์‚ดํŽด๋ณด๊ธฐ

์š”์ฆ˜์€ ๋Œ€๋‹ค์ˆ˜์˜ ์ดˆ์ฝœ๋ฆฟ ๊ณต์žฅ์—์„œ ์ดˆ์ฝœ๋ฆฟ์„ ๋“์ด๋Š” ์žฅ์น˜(์ดํ•˜ โ€˜์ดˆ์ฝœ๋ฆฟ ๋ณด์ผ๋Ÿฌโ€™๋กœ ์ง€์นญ)๋ฅผ ์ปดํ“จํ„ฐ๋กœ ์ œ์–ดํ•œ๋‹ค. ์ดˆ์ฝœ๋ฆฟ ๋ณด์ผ๋Ÿฌ๋Š” ์ดˆ์ฝœ๋ฆฟ๊ณผ ์šฐ์œ ๋ฅผ ๋ฐ›์•„์„œ ๋“์ด๊ณ  ์ดˆ์ฝ”๋ฐ”๋ฅผ ๋งŒ๋“œ๋Š” ๋‹จ๊ณ„๋กœ ๋„˜๊ฒจ์ค€๋‹ค. ์•„๋ž˜์—๋Š” ์ตœ์‹ ํ˜• ์ดˆ์ฝœ๋ฆฟ ๋ณด์ผ๋Ÿฌ๋ฅผ ์ œ์–ดํ•˜๋Š” ํด๋ž˜์Šค๊ฐ€ ๋‚˜์™€ ์žˆ๋‹ค.

์ดˆ์ฝœ๋ฆฟ ๊ณต์žฅ์—์„œ ์‚ฌ์šฉํ•˜๋Š” ์žฅ์น˜์ธ ์ดˆ์ฝœ๋ฆฟ ๋ณด์ผ๋Ÿฌ๋Š” ๋‹ค์Œ์˜ ์ˆœ์„œ๋ฅผ ๋”ฐ๋ผ ์ž‘๋™ํ•œ๋‹ค.

  1. ์ดˆ์ฝœ๋ฆฟ๊ณผ ์šฐ์œ ๋ฅผ ์ฑ„์šด๋‹ค
  2. ๋ณด์ผ๋Ÿฌ๋ฅผ ๊ฐ€์—ดํ•ด ๋“์ธ๋‹ค
  3. ๋‹ค ๋“์€ ์žฌ๋ฃŒ๋ฅผ ๋‹ค์Œ ๊ณต์ •์ธ ์ดˆ์ฝ”๋ฐ” ๋งŒ๋“ค๊ธฐ๋กœ ๋„˜๊ธด๋‹ค

๋‹ค์Œ๊ณผ ๊ฐ™์€ ์‹ค์ˆ˜๋Š” ๋ง‰๋Š”๋‹ค.

  • ์•„์ง ๋“์ง€ ์•Š์€ ์žฌ๋ฃŒ 500๊ฐค๋Ÿฐ์„ ๊ทธ๋ƒฅ ํ˜๋ ค ๋ฒ„๋ฆฐ๋‹ค. โŒ
  • ๋ณด์ผ๋Ÿฌ๊ฐ€ ๊ฐ€๋“ ์ฐจ ์žˆ๋Š” ์ƒํƒœ์—์„œ ์ƒˆ๋กœ์šด ์žฌ๋ฃŒ๋ฅผ ๋ถ“๋Š”๋‹ค. โŒ
  • ๋นˆ ๋ณด์ผ๋Ÿฌ๋ฅผ ๋“์ธ๋‹ค. โŒ
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public class ChocolateBoiler {
    private boolean empty;
    private boolean boiled;

    public ChocolateBoiler() {
        empty = true;
        boiled = false;
    }

    public void fill() {
        if (isEmpty()) {
            empty = false;
            boiled = false;
        }
    }

    public void boil() {
        if (!isEmpty() && !isBoiled()) {
            boiled = true;
        }
    }

    public void drain() {
        if (!isEmpty() && isBoiled()) {
            empty = true;
        }
    }

    public boolean isEmpty() {
        return empty;
    }

    public boolean isBoiled() {
        return boiled;
    }
}

ํ•˜์ง€๋งŒ 2๊ฐœ์˜ ChocolateBoiler ์ธ์Šคํ„ด์Šค๊ฐ€ ๋”ฐ๋กœ ๋Œ์•„๊ฐ€๋ฉด ์ƒ๋‹นํžˆ ์•ˆ ์ข‹์€ ์ƒํ™ฉ์ด ์ผ์–ด๋‚  ์ˆ˜ ์žˆ๋‹ค.\๋งŒ์•ฝ ํ•œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ChocolateBoiler ์ธ์Šคํ„ด์Šค๊ฐ€ 2๊ฐœ ์ด์ƒ ๋งŒ๋“ค์–ด์ง€๋ฉด ์–ด๋–ค ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธธ ์ˆ˜ ์žˆ์„๊นŒ?

๐Ÿซย ์‹ฑ๊ธ€ํ„ด ํŒจํ„ด์˜ ์ •์˜

์‹ฑ๊ธ€ํ„ด ํŒจํ„ด(Singleton Pattern)์€ ํด๋ž˜์Šค ์ธ์Šคํ„ด์Šค๋ฅผ ํ•˜๋‚˜๋งŒ ๋งŒ๋“ค๊ณ , ๊ทธ ์ธ์Šคํ„ด์Šค๋กœ์˜ ์ „์—ญ ์ ‘๊ทผ์„ ์ œ๊ณตํ•œ๋‹ค.

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

Image

๐Ÿ”น static uniqueInstance

  • ์‹ฑ๊ธ€ํ„ด ๊ฐ์ฒด๋ฅผ ํด๋ž˜์Šค ์ˆ˜์ค€์—์„œ ์ €์žฅํ•˜๋Š” ์ •์  ๋ณ€์ˆ˜
  • ๋”ฑ ํ•˜๋‚˜์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์ €์žฅํ•ด ๋†“์Œ

๐Ÿ”น static getInstance()

  • ์‹ฑ๊ธ€ํ„ด์˜ ํ•ต์‹ฌ ๋ฉ”์„œ๋“œ
  • Singleton.getInstance()๋ผ๋Š” ์ฝ”๋“œ๋งŒ ์‚ฌ์šฉํ•˜๋ฉด ์–ธ์ œ ์–ด๋””์„œ๋“  ์ด ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์Œ
  • ๊ฒŒ์œผ๋ฅธ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์žฅ์  (= ํ•„์š”ํ•  ๋•Œ๊นŒ์ง€ ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค์ง€ ์•Š๋Š”๋‹ค)

๐Ÿซย ์ดˆ์ฝœ๋ฆฟ ๋ณด์ผ๋Ÿฌ์— ๋ฌธ์ œ ๋ฐœ์ƒ

๊ณ ์ „์ ์ธ ์‹ฑ๊ธ€ํ„ด ํŒจํ„ด์œผ๋กœ ์ฝ”๋“œ๋ฅผ ๊ณ ์ณค์Œ์—๋„ ChocolateBoiler์— ์žˆ๋Š” fill() ๋ฉ”์†Œ๋“œ์—์„œ ์•„์ง ์ดˆ์ฝœ๋ฆฟ์ด ๋“๊ณ  ์žˆ๋Š”๋ฐ ์ƒˆ๋กœ์šด ์žฌ๋ฃŒ๋ฅผ ๋„ฃ๊ณ  ๋ง์•˜๋‹ค. ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋„๋ก ์ดˆ์ฝœ๋ฆฟ ๋ณด์ผ๋Ÿฌ ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ์ตœ์ ํ™”์‹œ์ผฐ์„ ๋ฟ์ธ๋ฐโ€ฆ!

Image

Step 1. Thread 1์ด getInstance()๋ฅผ ํ˜ธ์ถœํ•จ

  • uniqueInstance๊ฐ€ null์ธ์ง€ ํ™•์ธ โ†’ true
  • Thread 1์€ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๋ ค๊ณ  ํ•จ

Step 2. ๋™์‹œ์— Thread 2๋„ getInstance()๋ฅผ ํ˜ธ์ถœํ•จ

  • uniqueInstance๊ฐ€ ์—ฌ์ „ํžˆ null (Thread A๊ฐ€ ์•„์ง ์ƒ์„ฑ ์•ˆ ๋๋ƒ„)
  • Thread 2๋„ ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ

๊ฒฐ๊ณผ: ์ธ์Šคํ„ด์Šค๊ฐ€ ๋‘ ๋ฒˆ ์ƒ์„ฑ๋จ

  • Thread 1 โ†’ Singleton ์ธ์Šคํ„ด์Šค 1 ์ƒ์„ฑ
  • Thread 2 โ†’ Singleton ์ธ์Šคํ„ด์Šค 2 ์ƒ์„ฑ

์™œ ๋ฌธ์ œ๋ƒ?

์‹ฑ๊ธ€ํ„ด์€ ํ•˜๋‚˜๋งŒ ์žˆ์–ด์•ผ ํ•˜๋Š”๋ฐ, ๋™์‹œ์— ๋งŒ๋“ค์–ด์„œ ๋‘ ๊ฐœ๊ฐ€ ๋˜์–ด๋ฒ„๋ฆฐ ๊ฑฐ

  • ํ”„๋กœ๊ทธ๋žจ์ด ์ „์—ญ์—์„œ ๊ฐ™์€ ๊ฐ์ฒด๋ฅผ ๊ณต์œ ํ•  ๊ฑฐ๋ผ๊ณ  ๋ฏฟ๊ณ  ์‚ฌ์šฉํ•˜๋Š”๋ฐ
  • ์•Œ๊ณ  ๋ณด๋‹ˆ ๊ฐ์ž ๋‹ค๋ฅธ ๊ฑธ ์“ฐ๊ณ  ์žˆ์Œ โ†’ ๋ฒ„๊ทธ ๋ฐœ์ƒ ๊ฐ€๋Šฅ

๐Ÿซย ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋”ฉ ๋ฌธ์ œ ํ•ด๊ฒฐํ•˜๊ธฐ

getInstance()๋ฅผ ๋™๊ธฐํ™”ํ•˜๋ฉด ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋”ฉ๊ณผ ๊ด€๋ จ๋œ ๋ฌธ์ œ๊ฐ€ ๊ฐ„๋‹จํ•˜๊ฒŒ ํ•ด๊ฒฐ๋œ๋‹ค.

1
2
3
4
5
6
public static synchronized Singleton getInstance() {
    if (uniqueInstance == null) {
        uniqueInstance = new Singleton();
    }
    return uniqueInstance;
}

synchronized ํ‚ค์›Œ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ฒŒ ๋˜๋ฉด ํ•œ ์Šค๋ ˆ๋“œ๊ฐ€ ๋ฉ”์†Œ๋“œ ์‚ฌ์šฉ์„ ๋๋‚ด๊ธฐ ์ „๊นŒ์ง€ ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ๋Š” ๊ธฐ๋‹ค๋ ค์•ผ ํ•œ๋‹ค. ์ฆ‰, 2๊ฐœ์˜ ์Šค๋ ˆ๋“œ๊ฐ€ ์ด ๋ฉ”์†Œ๋“œ๋ฅผ ๋™์‹œ์— ์‹คํ–‰ํ•˜๋Š” ์ผ์€ ์ผ์–ด๋‚˜์ง€ ์•Š๋Š”๋‹ค.

์ด๋Ÿฌ๋ฉด ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ๋˜๊ธด ํ•˜๊ฒ ์ง€๋งŒ, ๋™๊ธฐํ™”ํ•  ๋•Œ ์†๋„ ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธฐ์ง€ ์•Š๋‚˜์š”?

๋งž์Œ.

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

๐Ÿซย ๋” ํšจ์œจ์ ์œผ๋กœ ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋”ฉ ๋ฌธ์ œ ํ•ด๊ฒฐํ•˜๊ธฐ

๋ฐฉ๋ฒ• 1

getInstance()์˜ ์†๋„๊ฐ€ ๊ทธ๋ฆฌ ์ค‘์š”ํ•˜์ง€ ์•Š๋‹ค๋ฉด ๊ทธ๋ƒฅ ๋‘”๋‹ค.

๋ฐฉ๋ฒ• 2

์ธ์Šคํ„ด์Šค๊ฐ€ ํ•„์š”ํ•  ๋•Œ๋Š” ์ƒ์„ฑํ•˜์ง€ ๋ง๊ณ  ์ฒ˜์Œ๋ถ€ํ„ฐ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

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

  • ์ •์  ์ดˆ๊ธฐํ™” ๋ถ€๋ถ„์—์„œ Singleton์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•œ๋‹ค. ์ด๋Ÿฌ๋ฉด ์Šค๋ ˆ๋“œ๋ฅผ ์จ๋„ ๋ณ„ ๋ฌธ์ œ๊ฐ€ ์—†๋‹ค.
1
2
3
4
5
6
7
8
9
class Singleton {
  private static instance: Singleton = new Singleton(); // ์• ์ดˆ์— ๋งŒ๋“ค์–ด ๋†“์Œ

  private constructor() {}

  public static getInstance(): Singleton {
    return this.instance;
  }
}

๋ฐฉ๋ฒ• 3

โ€˜DCLโ€™์„ ์จ์„œ getInstance()์—์„œ ๋™๊ธฐํ™”๋˜๋Š” ๋ถ€๋ถ„์„ ์ค„์ž…๋‹ˆ๋‹ค.

Double-Checked Locking, DCL์„ ์‚ฌ์šฉํ•˜๋ฉด ์ธ์Šคํ„ด์Šค๊ฐ€ ์ƒ์„ฑ๋˜์–ด ์žˆ๋Š”์ง€ ํ™•์ธํ•œ ๋‹ค์Œ ์ƒ์„ฑ๋˜์–ด ์žˆ์ง€ ์•Š์•˜์„ ๋•Œ๋งŒ ๋™๊ธฐํ™”ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋Ÿฌ๋ฉด ์ฒ˜์Œ์—๋งŒ ๋™๊ธฐํ™”ํ•˜๊ณ  ๋‚˜์ค‘์—๋Š” ๋™๊ธฐํ™”ํ•˜์ง€ ์•Š์•„๋„ ๋œ๋‹ค.

  • volatile ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋”ฉ์„ ์“ฐ๋”๋ผ๋„ uniqueInstance ๋ณ€์ˆ˜๊ฐ€ Singleton ์ธ์Šคํ„ด์Šค๋กœ ์ดˆ๊ธฐํ™”๋˜๋Š” ๊ณผ์ •์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ง„ํ–‰๋œ๋‹ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Singleton {
  private volatile static Singleton uniqueInstance;

  private Singleton() {}

  public static Singleton getInstance() {
  // ์ธ์Šคํ„ด์Šค๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๊ณ , ์—†์œผ๋ฉด ๋™๊ธฐํ™”๋œ ๋ธ”๋ก์œผ๋กœ ๋“ค์–ด๊ฐ
    if (uniqueInstance == null) {
      synchronized(Singleton.class) {
        if (uniqueInstance == null) {
          uniqueInstance = new Singleton();
        }
      }
    }
    return uniqueInstance;
  }
}

๐Ÿซย ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ์ ์ ˆํ•œ ๋ฐฉ๋ฒ• ์„ ํƒํ•˜๊ธฐ

1. synchronized ๋ฐฉ์‹ (๋™๊ธฐํ™”๋œ ๋ฉ”์„œ๋“œ)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
public class ChocolateBoiler {
    private boolean empty;
    private boolean boiled;

    private static ChocolateBoiler uniqueInstance;

    // ์ƒ์„ฑ์ž๋Š” private โ€“ ์™ธ๋ถ€์—์„œ new ๋ชป ํ•˜๊ฒŒ ๋ง‰์Œ
    private ChocolateBoiler() {
        empty = true;
        boiled = false;
    }

    // getInstance()์— synchronized ๋ถ™์—ฌ์„œ ์Šค๋ ˆ๋“œ ํ•˜๋‚˜๋งŒ ์ ‘๊ทผ ๊ฐ€๋Šฅ
    public static synchronized ChocolateBoiler getInstance() {
        if (uniqueInstance == null) {
            uniqueInstance = new ChocolateBoiler();
        }
        return uniqueInstance;
    }

    public void fill() {
        if (isEmpty()) {
            empty = false;
            boiled = false;
        }
    }

    public void boil() {
        if (!isEmpty() && !isBoiled()) {
            boiled = true;
        }
    }

    public void drain() {
        if (!isEmpty() && isBoiled()) {
            empty = true;
        }
    }

    public boolean isEmpty() {
        return empty;
    }

    public boolean isBoiled() {
        return boiled;
    }
}


โœ… ์žฅ์ 

  • ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ ํ™˜๊ฒฝ์—์„œ ์•ˆ์ „

    ์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ๊ฐ€ ๋™์‹œ์— ์ ‘๊ทผํ•ด๋„ ๋‹จ ํ•˜๋‚˜์˜ ์ธ์Šคํ„ด์Šค๋งŒ ์ƒ์„ฑ

  • ๊ตฌํ˜„์ด ๋‹จ์ˆœ

โŒ ๋‹จ์ 

  • ๋งค๋ฒˆ ๋ฝ์„ ๊ฑธ๊ธฐ ๋•Œ๋ฌธ์— ์„ฑ๋Šฅ ์ €ํ•˜๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Œ
  • ํŠนํžˆ ์ธ์Šคํ„ด์Šค๊ฐ€ ์ด๋ฏธ ๋งŒ๋“ค์–ด์ง„ ์ดํ›„์—๋„ getInstance()๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ๋งˆ๋‹ค ๋ฝ์„ ๊ฑฐ๋Š” ๊ฑด ๋‚ญ๋น„

2. ์ด๋ฅธ ์ดˆ๊ธฐํ™” (Eager Initialization)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
public class ChocolateBoiler {
    private boolean empty;
    private boolean boiled;

    // ์ธ์Šคํ„ด์Šค๋ฅผ ์• ์ดˆ์— ๋งŒ๋“ค์–ด๋ฒ„๋ฆผ (JVM ๋กœ๋”ฉ ์‹œ์ ์—)
    private static final ChocolateBoiler uniqueInstance = new ChocolateBoiler();

    private ChocolateBoiler() {
        empty = true;
        boiled = false;
    }

    public static ChocolateBoiler getInstance() {
        return uniqueInstance;
    }

    public void fill() {
        if (isEmpty()) {
            empty = false;
            boiled = false;
        }
    }

    public void boil() {
        if (!isEmpty() && !isBoiled()) {
            boiled = true;
        }
    }

    public void drain() {
        if (!isEmpty() && isBoiled()) {
            empty = true;
        }
    }

    public boolean isEmpty() {
        return empty;
    }

    public boolean isBoiled() {
        return boiled;
    }
}


โœ… ์žฅ์ 

  • ์ฝ”๋“œ๊ฐ€ ๊ฐ€์žฅ ๊ฐ„๋‹จํ•˜๊ณ , ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ ์•ˆ์ „
  • ํด๋ž˜์Šค๊ฐ€ ๋กœ๋”ฉ๋  ๋•Œ ์ธ์Šคํ„ด์Šค๊ฐ€ ๋”ฑ ํ•œ ๋ฒˆ ๋งŒ๋“ค์–ด์ง€๊ณ  ๋
  • ์ดํ›„ ์ ‘๊ทผ ์†๋„๊ฐ€ ๋น ๋ฅด๋‹ค. ๋ฝ์ด ํ•„์š” X

โŒ ๋‹จ์ 

  • ์“ฐ๋“  ์•ˆ ์“ฐ๋“  ๋ฌด์กฐ๊ฑด ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“ค๊ธฐ ๋•Œ๋ฌธ์— ๋ฉ”๋ชจ๋ฆฌ ๋‚ญ๋น„ ๊ฐ€๋Šฅ
  • ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“œ๋Š” ๋ฐ ์‹œ๊ฐ„์ด ์˜ค๋ž˜ ๊ฑธ๋ฆฌ๋Š” ๊ฒฝ์šฐ, ์•ฑ ๋กœ๋”ฉ ์ง€์—ฐ ๋ฐœ์ƒ ๊ฐ€๋Šฅ

3. Double-Checked Locking (์ด์ค‘ ๊ฒ€์‚ฌ ์ž ๊ธˆ)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
public class ChocolateBoiler {
    private boolean empty;
    private boolean boiled;

    // volatile: ์Šค๋ ˆ๋“œ ๊ฐ„ ๋ฉ”๋ชจ๋ฆฌ ์ผ๊ด€์„ฑ ๋ณด์žฅ
    private volatile static ChocolateBoiler uniqueInstance;

    private ChocolateBoiler() {
        empty = true;
        boiled = false;
    }

    public static ChocolateBoiler getInstance() {
        if (uniqueInstance == null) {
            synchronized (ChocolateBoiler.class) {
                if (uniqueInstance == null) {
                    uniqueInstance = new ChocolateBoiler();
                }
            }
        }
        return uniqueInstance;
    }

    public void fill() {
        if (isEmpty()) {
            empty = false;
            boiled = false;
        }
    }

    public void boil() {
        if (!isEmpty() && !isBoiled()) {
            boiled = true;
        }
    }

    public void drain() {
        if (!isEmpty() && isBoiled()) {
            empty = true;
        }
    }

    public boolean isEmpty() {
        return empty;
    }

    public boolean isBoiled() {
        return boiled;
    }
}

โœ… ์žฅ์ 

  • ์ตœ์ดˆ ํ•œ ๋ฒˆ๋งŒ ๋ฝ์„ ๊ฑธ๊ธฐ ๋•Œ๋ฌธ์— ์„ฑ๋Šฅ์ด ์ข‹๋‹ค.
  • ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ ํ™˜๊ฒฝ์—์„œ๋„ ์•ˆ์ „ํ•˜๊ณ , ์ด๋ฏธ ์ธ์Šคํ„ด์Šค๊ฐ€ ๋งŒ๋“ค์–ด์กŒ์œผ๋ฉด ๋ฝ ์—†์ด ๋น ๋ฅด๊ฒŒ ๋ฆฌํ„ด๋จ

โŒ ๋‹จ์ 

  • ๊ตฌํ˜„์ด ๊ฐ€์žฅ ๋ณต์žกํ•˜๋‹ค.
  • ์‹ค์ˆ˜ํ•˜๋ฉด ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ ๋ฒ„๊ทธ๊ฐ€ ์ƒ๊ธธ ์ˆ˜ ์žˆ์Œ
  • ์ž๋ฐ” 1.4 ์ดํ•˜์—์„œ๋Š” volatile ๋ฌธ์ œ๋กœ ์™„์ „ํžˆ ์•ˆ์ „ํ•˜์ง€ ์•Š์Œ (์š”์ฆ˜์—” ๋Œ€๋ถ€๋ถ„ ๊ดœ์ฐฎ)

โœจ ์–ธ์ œ ๋ญ˜ ์จ์•ผ ํ• ๊นŒ?

  • ์„ฑ๋Šฅ๋ณด๋‹ค ๋‹จ์ˆœํ•œ ์ฝ”๋“œ๊ฐ€ ์ค‘์š”ํ•˜๋ฉด โ†’ synchronized
  • ์ธ์Šคํ„ด์Šค๋ฅผ ๋ฌด์กฐ๊ฑด ์“ธ ๊ฑฐ๊ณ  ๋น ๋ฅธ ์†๋„๊ฐ€ ํ•„์š”ํ•˜๋ฉด โ†’ eager
  • ์ •๋ง ํšจ์œจ์ด ์ค‘์š”ํ•œ ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ ํ™˜๊ฒฝ์ด๋ฉด โ†’ DCL

๐Ÿซย ๋ฐฉ๊ธˆ ๊นจ๋‹ฌ์•˜๋Š”๋ฐ์š”โ€ฆ

enum์„ ์‚ฌ์šฉํ•˜๋ฉด ์‹ฑ๊ธ€ํ„ด์˜ ์—ฌ๋Ÿฌ ๋ฌธ์ œ์ ์„ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ ๊ฐ™์•„์š”.

์ข‹์€ ์ƒ๊ฐ์ž…๋‹ˆ๋‹ค!

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

๐Ÿง  ์™œ enum์œผ๋กœ ์‹ฑ๊ธ€ํ„ด์„ ๋งŒ๋“ค๋ฉด ์ข‹์„๊นŒ?

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

1
2
3
4
5
6
7
8
9
10
public enum ChocolateBoiler {
    INSTANCE; // ๋‹จ ํ•˜๋‚˜์˜ ์ธ์Šคํ„ด์Šค (Singleton)

    private boolean empty = true;
    private boolean boiled = false;

    public void fill() { ... }
    public void boil() { ... }
    public void drain() { ... }
}
This post is licensed under CC BY 4.0 by the author.