๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
Programming Language ๐Ÿ’ป/Java โ˜•

[Java] ๊ฐ์ฒด์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ(OOP) - ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด(Singleton Pattern)์ด๋ž€?

by lxvxxu 2025. 10. 18.

2025.10.18 - [๋ถ„๋ฅ˜ ์ „์ฒด๋ณด๊ธฐ] - [Java] ๊ฐ์ฒด์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ(OOP) - 3. ๋””์ž์ธ ํŒจํ„ด์ด๋ž€?

 

[Java] ๊ฐ์ฒด์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ(OOP) - 3. ๋””์ž์ธ ํŒจํ„ด์ด๋ž€?

3) ๋””์ž์ธ ํŒจํ„ด์ด๋ž€? ๐Ÿง ๋ฐ˜๋ณต๋˜๋Š” ์„ค๊ณ„ ๋ฌธ์ œ์— ๋Œ€ํ•œ ๊ฒ€์ฆ๋œ “์ด๋ฆ„ ์žˆ๋Š” ํ•ด๋ฒ•”์˜ ์นดํƒˆ๋กœ๊ทธ์žฅ์ : ๊ณตํ†ต ์–ดํœ˜ ์ œ๊ณต(์˜์‚ฌ์†Œํ†ต↑), ์žฌ์‚ฌ์šฉ์„ฑ↑, ์œ ์ง€๋ณด์ˆ˜์„ฑ↑์ฃผ์˜: “ํŒจํ„ด ์ ์šฉ์„ ์œ„ํ•ด ๋ฌธ์ œ๋ฅผ ์–ต์ง€๋กœ

lxvxxu.tistory.com


 

๐Ÿงฉ ๋””์ž์ธ ํŒจํ„ด โ‘ฅ — ์‹ฑ๊ธ€ํ†ค(Singleton) ํŒจํ„ด

“๊ฐ์ฒด๋ฅผ ๋‹จ ํ•˜๋‚˜๋งŒ ๋งŒ๋“ค๊ณ , ์–ด๋””์„œ๋“  ๋™์ผํ•œ ์ธ์Šคํ„ด์Šค๋ฅผ ์“ฐ์ž!”


๐ŸŽฏ ํ•™์Šต ๋ชฉํ‘œ

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

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

ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์˜ค์ง ํ•œ ๊ฐœ๋งŒ ๋งŒ๋“ค๊ณ , ์ „์—ญ์ ์œผ๋กœ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•˜๋Š” ํŒจํ„ด

๐Ÿ“‹ ์ •์˜

Ensure a class only has one instance, and provide a global point of access to it.

์š”์†Œ์„ค๋ช…
์ด๋ฆ„ ์‹ฑ๊ธ€ํ†ค(Singleton)
๋ฌธ์ œ ์—ฌ๋Ÿฌ ๊ฐ์ฒด๊ฐ€ ์ƒ์„ฑ๋˜๋ฉด ์ƒํƒœ ๊ด€๋ฆฌ๊ฐ€ ์–ด๋ ค์›€
ํ•ด๊ฒฐ ๊ฐ์ฒด ์ƒ์„ฑ์„ ์ค‘์•™์—์„œ ๊ด€๋ฆฌ
๊ฒฐ๊ณผ ๊ฐ์ฒด๊ฐ€ 1๊ฐœ๋งŒ ์กด์žฌํ•˜์—ฌ ์ผ๊ด€๋œ ์ƒํƒœ ์œ ์ง€

๐Ÿงฉ ๊ธฐ๋ณธ ๊ตฌํ˜„๋ฒ•

๐Ÿงฑ ๊ณ ์ „์ ์ธ ์‹ฑ๊ธ€ํ†ค ๊ตฌํ˜„ ๋ฐฉ์‹

public class Printer {
    private static Printer printer = null;  // ์œ ์ผํ•œ ์ธ์Šคํ„ด์Šค ์ €์žฅ ๊ณต๊ฐ„

    private Printer() { } // ์ƒ์„ฑ์ž ๋น„๊ณต๊ฐœ

    public static Printer getPrinter() {
        if (printer == null) {
            printer = new Printer();
        }
        return printer;
    }

    public void print(String str) {
        System.out.println(str);
    }
}
public class User {
    private String name;
    public User(String name) { this.name = name; }

    public void print() {
        Printer printer = Printer.getPrinter();
        printer.print(this.name + " print using " + printer.toString());
    }
}
 

โžก๏ธ ๋ชจ๋“  User ๊ฐ์ฒด๊ฐ€ ๊ฐ™์€ Printer ์ธ์Šคํ„ด์Šค๋ฅผ ๊ณต์œ ํ•จ.


โš ๏ธ ๋ฌธ์ œ์  — ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ ํ™˜๊ฒฝ

๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ ํ™˜๊ฒฝ์—์„œ๋Š” ๋™์‹œ์— ์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ๊ฐ€ getPrinter()๋ฅผ ํ˜ธ์ถœํ•  ๊ฒฝ์šฐ
์—ฌ๋Ÿฌ ๊ฐœ์˜ ์ธ์Šคํ„ด์Šค๊ฐ€ ์ƒ์„ฑ๋  ์ˆ˜ ์žˆ์Œ.

3-thread print using Printer@6653aac1
4-thread print using Printer@1deddeb6
→ ์„œ๋กœ ๋‹ค๋ฅธ ์ธ์Šคํ„ด์Šค ์‚ฌ์šฉ!
→ ์„œ๋กœ ๋‹ค๋ฅธ ์ธ์Šคํ„ด์Šค ์‚ฌ์šฉ!

๐Ÿงฐ ํ•ด๊ฒฐ์ฑ…

1๏ธโƒฃ ์ •์  ์ดˆ๊ธฐํ™” ๋ฐฉ์‹

public class Singleton {
    private static final Singleton instance = new Singleton();
    private Singleton() { }
    public static Singleton getInstance() {
        return instance;
    }
}
 

โœ… ์•ˆ์ „ํ•˜์ง€๋งŒ, ํ”„๋กœ๊ทธ๋žจ ์‹œ์ž‘ ์‹œ ๋ฌด์กฐ๊ฑด ์ธ์Šคํ„ด์Šค๊ฐ€ ๋งŒ๋“ค์–ด์ง (๋น„ํšจ์œจ ๊ฐ€๋Šฅ)


2๏ธโƒฃ ๋™๊ธฐํ™” ๋ฐฉ์‹ (Synchronized)

 
public class Singleton {
    private static Singleton instance;
    private Singleton() { }

    public static synchronized Singleton getInstance() {
        if (instance == null) instance = new Singleton();
        return instance;
    }
}

โœ… Thread-safe
โŒ ๋™๊ธฐํ™”๋กœ ์ธํ•ด ์„ฑ๋Šฅ ์ €ํ•˜ ๊ฐ€๋Šฅ


3๏ธโƒฃ DCL (Double-Checked Locking)

Java 5 ์ด์ƒ์—์„œ ๊ถŒ์žฅ๋˜๋Š” ๊ณ ๊ธ‰ ๋ฐฉ๋ฒ•

public class Singleton {
    private volatile static Singleton instance;

    private Singleton() { }

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

๐Ÿงฉ volatile → ์บ์‹œ ๋Œ€์‹  ๋ฉ”๋ชจ๋ฆฌ์—์„œ ์ง์ ‘ ์ฝ์Œ
๐Ÿงฉ synchronized → ๋™์‹œ์— ํ•œ ์Šค๋ ˆ๋“œ๋งŒ ์ ‘๊ทผํ•˜๋„๋ก ๋ฝ(lock) ๊ฑธ๊ธฐ


๐Ÿซ ์‚ฌ๋ก€ 2 — ์ดˆ์ฝœ๋ฆฟ ๊ณต์žฅ ์ œ์–ด ์‹œ์Šคํ…œ

์ดˆ์ฝœ๋ฆฟ๊ณผ ์šฐ์œ ๋ฅผ ํ˜ผํ•ฉํ•˜๊ณ  ๋“์ด๋Š” ๋ณด์ผ๋Ÿฌ(Boiler) ๋Š” ๋ฐ˜๋“œ์‹œ ํ•œ ๊ฐœ๋งŒ ์กด์žฌํ•ด์•ผ ํ•œ๋‹ค.

public class ChocolateBoiler {
    private static ChocolateBoiler uniqueInstance;
    private boolean empty;
    private boolean boiled;

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

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

    // fill(), boil(), drain() ๋“ฑ ๋ณด์ผ๋Ÿฌ ์ œ์–ด ์ฝ”๋“œ...
}

โœ… ๋‹จ ํ•˜๋‚˜์˜ ๋ณด์ผ๋Ÿฌ๋งŒ ์กด์žฌํ•˜๋ฏ€๋กœ
“์ค‘๋ณต ์ž‘์—…”, “๋ฐ์ดํ„ฐ ๋ถˆ์ผ์น˜” ๋“ฑ์„ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ์Œ.


๐Ÿ”š ์ •๋ฆฌ

ํ•ญ๋ชฉ๋‚ด์šฉ
ํ•ต์‹ฌ ๊ฐœ๋… ๊ฐ์ฒด๋ฅผ ํ•˜๋‚˜๋งŒ ๋งŒ๋“ค๊ณ , ์ „์—ญ์ ์œผ๋กœ ์ ‘๊ทผ
์žฅ์  ์ž์› ๋‚ญ๋น„ ๋ฐฉ์ง€, ๋ฐ์ดํ„ฐ ์ผ๊ด€์„ฑ ์œ ์ง€
๋‹จ์  ํ…Œ์ŠคํŠธ ์–ด๋ ค์›€, ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ ์‹œ ์ฃผ์˜ ํ•„์š”
๋Œ€ํ‘œ ์˜ˆ์‹œ Logger, ์„ค์ • ๊ด€๋ฆฌ์ž, Connection Pool ๋“ฑ