๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

๊ณณ๊ฐ„์—์„œ ์ธ์‹ฌ๋‚œ๋‹ค

[Java] Thread-Safeํ•œ Singleton ๊ฐ์ฒด

์ถœ์ฒ˜

ChatGPT

https://simyeju.tistory.com/121

 

Java] Multi Thread ํ™˜๊ฒฝ์—์„œ Singleton ํŒจํ„ด์„ Thread Safeํ•˜๊ฒŒ ์‚ฌ์šฉํ•˜๊ธฐ

Multi Thread ํ™˜๊ฒฝ์—์„œ Singleton ํŒจํ„ด์„ Thread Safeํ•˜๊ฒŒ ์‚ฌ์šฉํ•˜๊ธฐ ํ•ด๋‹น ๊ธ€๊ณผ ๊ด€๋ จ๋œ Singleton Pattern์„ ํ…Œ์ŠคํŠธ ํ•ด๋ณผ ์ˆ˜ ์žˆ๋Š” git์ฃผ์†Œ๋ฅผ ์ฒจ๋ถ€ํ•ฉ๋‹ˆ๋‹ค ๐Ÿ— https://github.com/SimYeJu/HelloSingletonPattern/tree/main/src โ“Single

simyeju.tistory.com

https://www.initgrep.com/posts/design-patterns/thread-safety-in-java-singleton-pattern

 

Explore Different Ways to Implement Thread-Safe Singleton Pattern in Java

Discover how to achieve thread safety in Java Singleton patterns. Explore methods like eager and lazy initialization, double-checked locking, Bill Pugh Singleton and enum Singletons for robust concurrency control.

www.initgrep.com

F-Lab Android Pepe ๋ฉ˜ํ† ๋‹˜


๊ด€๋ จ ๊ฐœ๋…

Singleton ํŒจํ„ด

๊ฐ์ฒด๋ฅผ ์˜ค์ง ํ•˜๋‚˜๋งŒ ์ƒ์„ฑํ•˜๋„๋ก ๋ณด์žฅํ•˜๋Š” ๋””์ž์ธ ํŒจํ„ด. ํ”„๋กœ๊ทธ๋žจ ์ „์ฒด์— ํ•˜๋‚˜์˜ ์ธ์Šคํ„ด์Šค๋งŒ ํ•„์š”ํ•˜๊ณ , ๊ทธ ์ธ์Šคํ„ด์Šค์— ์ „์—ญ์ ์œผ๋กœ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋„๋กํ•˜๋Š” ์ƒํ™ฉ์—์„œ ์œ ์šฉํ•˜๋‹ค.

-> OOP ํ™˜๊ฒฝ์—์„œ ์ „์—ญ ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์–ด์„œ ๋‚˜์˜จ ๊ฒƒ

Singleton ๊ฐ์ฒด

์‹ฑ๊ธ€ํ†ค ํŒจํ„ด์— ๋”ฐ๋ผ ์ƒ์„ฑ๋œ ๊ฐ์ฒด. ํ•ด๋‹น ํด๋ž˜์Šค์˜ ์œ ์ผํ•œ ์ธ์Šคํ„ด์Šค๋ฅผ ์˜๋ฏธํ•œ๋‹ค. 

์‹ฑ๊ธ€ํ†ค ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜๋Š” ๋Œ€ํ‘œ์ ์ธ ๊ฒฝ์šฐ

  • ์„ค์ • ๊ด€๋ฆฌ : ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ „๋ฐ˜์— ๊ฑธ์ณ ์ผ์ •ํ•œ ์„ค์ • ๊ฐ’์„ ์œ ์ง€ํ•  ํ•„์š”๊ฐ€ ์žˆ์„ ๋•Œ
  • ๋กœ๊ทธ ๊ธฐ๋ก : ํ”„๋กœ๊ทธ๋žจ ๋‚ด์˜ ๋ชจ๋“  ๋กœ๊ทธ๊ฐ€ ๋™์ผํ•œ ๋กœ๊ทธ ํŒŒ์ผ์— ๊ธฐ๋ก๋˜์–ด์•ผ ํ•  ๋•Œ
  • ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๊ฒฐ ๊ด€๋ฆฌ : ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๊ฒฐ์„ ํ•˜๋‚˜์˜ ์ธ์Šคํ„ด์Šค๋กœ ๊ด€๋ฆฌํ•˜๊ณ  ๊ณต์œ ํ•  ๋•Œ

Thread-Safe ์˜๋ฏธ

๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ ํ™˜๊ฒฝ์—์„œ ์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ๊ฐ€ ๋™์‹œ์— ๊ฐ™์€ ์ž์›์— ์ ‘๊ทผํ•˜๊ฑฐ๋‚˜ ์ˆ˜์ •ํ•˜๋ ค๊ณ  ํ•  ๋•Œ๋„, ํ”„๋กœ๊ทธ๋žจ์˜ ์‹คํ–‰ ๊ฒฐ๊ณผ๊ฐ€ ์ •ํ™•ํ•˜๊ณ  ์˜ˆ์ธก ๊ฐ€๋Šฅํ•œ ์ƒํƒœ๋กœ ์œ ์ง€๋˜๋Š” ๊ฒƒ

 

์‹ฑ๊ธ€ํ†ค ๊ฐ์ฒด๋ฅผ Thread-Safeํ•˜๊ฒŒ ๋งŒ๋“ค์–ด์•ผ ํ•˜๋Š” ์ด์œ 

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

1. ๋™์‹œ์„ฑ ๋ฌธ์ œ

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

์ด ๊ฒฝ์šฐ, ์„œ๋กœ ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ๊ฐ€ ๊ฐ๊ธฐ ๋‹ค๋ฅธ ์‹ฑ๊ธ€ํ†ค ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๊ฒŒ ๋  ์ˆ˜ ์žˆ์–ด ์‹ฑ๊ธ€ํ†ค์˜ ์œ ์ผ์„ฑ ์›์น™์ด ๊นจ์ง„๋‹ค.

2. ๋ฐ์ดํ„ฐ ์ผ๊ด€์„ฑ ์œ ์ง€

์‹ฑ๊ธ€ํ†ค ๊ฐ์ฒด๋Š” ์ฃผ๋กœ ์„ค์ •, ๋กœ๊น…, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๊ฒฐ, ๋ฆฌ์†Œ์Šค ๊ด€๋ฆฌ ๋“ฑ์˜ ๋ชฉ์ ์œผ๋กœ ์‚ฌ์šฉ๋˜๋ฉฐ, ์—ฌ๋Ÿฌ ๋ถ€๋ถ„์—์„œ ์ ‘๊ทผ์ด ์ผ์–ด๋‚˜๋ฏ€๋กœ ๋ฐ์ดํ„ฐ ์ผ๊ด€์„ฑ์ด ์ค‘์š”ํ•˜๋‹ค.

  • ๋ฐ์ดํ„ฐ ์ผ๊ด€์„ฑ Data Consistency : ์—ฌ๋Ÿฌ ์Šค๋ž˜๋“œ ๋˜๋Š” ํ”„๋กœ์„ธ์Šค๊ฐ€ ๋™์‹œ์— ์ ‘๊ทผํ•˜๊ฑฐ๋‚˜ ์ˆ˜์ •ํ•˜๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ํ•ญ์ƒ ์ •ํ™•ํ•˜๊ณ  ์˜ˆ์ธก ๊ฐ€๋Šฅํ•œ ์ƒํƒœ๋กœ ์œ ์ง€๋˜๋Š” ๊ฒƒ

Thread-Safeํ•˜์ง€ ์•Š๋‹ค๋ฉด, ์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ๊ฐ€ ๋™์‹œ์— ์ ‘๊ทผํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ๋ณ€๊ฒฝํ•˜๋ ค ํ•  ๋•Œ, ์ž˜๋ชป๋œ ๋ฐ์ดํ„ฐ ์ƒํƒœ๊ฐ€ ๋ฐœ์ƒํ•˜๊ฑฐ๋‚˜ ๊ฒฝํ•ฉ ์ƒํƒœ(race condition)์ด ์ผ์–ด๋‚  ์ˆ˜ ์žˆ๋‹ค.

  • ๊ฒฝํ•ฉ ์ƒํƒœ Race Condition : ์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ ๋˜๋Š” ํ”„๋กœ์„ธ์Šค๊ฐ€ ๋™์‹œ์— ๊ณต์œ  ์ž์›์— ์ ‘๊ทผํ•˜๊ฑฐ๋‚˜ ์ˆ˜์ •ํ•˜๋ ค ํ•  ๋•Œ ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ. ์ž‘์—…์˜ ์‹คํ–‰ ์ˆœ์„œ๊ฐ€ ์‹คํ–‰๋งˆ๋‹ค ๋‹ฌ๋ผ์ง€๋ฉด์„œ ์˜ˆ์ธกํ•  ์ˆ˜ ์—†๋Š” ๊ฒฐ๊ณผ๋ฅผ ์ดˆ๋ž˜ํ•  ์ˆ˜ ์žˆ๋‹ค.

3. ๋ฆฌ์†Œ์Šค ๋‚ญ๋น„ ๋ฐฉ์ง€

์‹ฑ๊ธ€ํ†ต ํŒจํ„ด์˜ ์ฃผ์š” ์žฅ์ ์€ ๊ฐ์ฒด๋ฅผ ํ•œ ๋ฒˆ๋งŒ ์ƒ์„ฑํ•ด ๋ฉ”๋ชจ๋ฆฌ์™€ ๊ฐ™์€ ๋ฆฌ์†Œ์Šค๋ฅผ ์ ˆ์•ฝํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

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

 

Thread-Safeํ•œ ์‹ฑ๊ธ€ํ†ค ๊ฐ์ฒด ์ƒ์„ฑ ๋ฐฉ๋ฒ•

1. ์ด๋ฅธ ์ดˆ๊ธฐํ™” Eager Initialization

ํด๋ž˜์Šค ๋กœ๋”ฉ ์‹œ์ ์— ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•ด ๊ฐ„๋‹จํ•˜๊ณ  ์Šค๋ ˆ๋“œ์— ์•ˆ์ „ํ•˜๋‹ค.

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

    private Singleton() {
        // private constructor to prevent instantiation
    }

    public static Singleton getInstance() {
        return instance;
    }
}

 

ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰ ์‹œ, ํด๋ž˜์Šค ๋กœ๋“œ์— ์˜ํ•ด ํด๋ž˜์Šค๊ฐ€ ๋กœ๋”ฉ๋  ๋•Œ static ์ œ์–ด์ž์— ์˜ํ•ด ๋ฏธ๋ฆฌ ์ธ์Šคํ„ด์Šค๊ฐ€ ์ƒ์„ฑ๋˜๋Š” ๋ฐฉ์‹

 

์žฅ์ 

๊ตฌํ˜„์ด ๋งค์šฐ ๊ฐ„๋”˜ํ•˜๋ฉฐ, ํด๋ž˜์Šค ๋กœ๋”ฉ ์‹œ์ ์— ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๋ฏ€๋กœ ์Šค๋ ˆ๋“œ ์•ˆ์ „์„ฑ์ด ๋ณด์žฅ๋œ๋‹ค.

๋‹จ์ 

๊ฐ์ฒด๊ฐ€ ํ•ญ์ƒ ์ƒ์„ฑ๋œ๋‹ค. ์‚ฌ์šฉํ•˜์ง€ ์•Š์„ ๊ฒฝ์šฐ ๋ฉ”๋ชจ๋ฆฌ ๋‚ญ๋น„๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ๋‹ค.

 

๐Ÿ˜ฎ ๋ฉ˜ํ† ๋‹˜์„ ํ†ตํ•ด ํด๋ž˜์Šค ๋กœ๋“œ ์‹œ์ ์„ ๊ณ ๋ คํ•ด์•ผ ํ•˜๋ฉด, 1๋ฒˆ์˜ Eager Initialization ๋ฐฉ๋ฒ•์œผ๋กœ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ๊ณผ 5๋ฒˆ์˜ ์ •์  ๋‚ด๋ถ€ ํด๋ž˜์Šค๋ฅผ ์ด์šฉํ•ด ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์˜ ํด๋ž˜์Šค ๋กœ๋“œ์™€ INSTANCE ์ƒ์„ฑ ์‹œ์ ์€ ๋™์ผํ•˜๋‹ค๋Š” ๊ฒƒ์„ ์•Œ์•˜๋‹ค.(1๋ฒˆ๊ณผ 5๋ฒˆ์ด ๋‚ด๋ถ€์ ์œผ๋กœ๋Š” ๋˜‘๊ฐ™๋‹ค๋Š” ๊ฑฐ) ํ•ด๋‹น ๋‚ด์šฉ ์„ค๋ช…์€ 5๋ฒˆ์—์„œ ํ•˜๊ฒ ๋‹ค.

 

2. Lazy Initialization

ํ•„์š”ํ•  ๋•Œ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฐฉ์‹. ๋‹จ์ˆœํ•˜๊ฒŒ ๊ตฌํ˜„ํ•˜๋ฉด ๋ฉ€ํ‹ฐ ์Šค๋ ˆ๋“œ ํ™˜๊ฒฝ์—์„œ ์•ˆ์ „ํ•˜์ง€ ์•Š๋‹ค. 

public class Singleton {
    private static Singleton instance;

    // private ์ƒ์„ฑ์ž
    private Singleton() {
    }

    // ์ธ์Šคํ„ด์Šค ๋ฐ˜ํ™˜ ๋ฉ”์„œ๋“œ
    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

 

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

 

3. Synchronized๋ฅผ ์‚ฌ์šฉํ•œ Lazy Initialization

getInstance() ๋ฉ”์†Œ๋“œ๋ฅผ synchronized๋กœ ๋งŒ๋“ค์–ด ์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ๊ฐ€ ๋™์‹œ์— ์ ‘๊ทผํ•˜์ง€ ๋ชปํ•˜๊ฒŒ ํ•œ๋‹ค.

public class Singleton {
    private static Singleton instance;

    // private ์ƒ์„ฑ์ž
    private Singleton() {
    }

    // ๋™๊ธฐํ™”๋œ ์ธ์Šคํ„ด์Šค ๋ฐ˜ํ™˜ ๋ฉ”์„œ๋“œ
    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

 

์žฅ์ 

์Šค๋ ˆ๋“œ ์•ˆ์ „์„ฑ์„ ๋ณด์žฅํ•œ๋‹ค.

๋‹จ์ 

getInstance() ๋ฉ”์†Œ๋“œ ํ˜ธ์ถœ ์‹œ๋งˆ๋‹ค lock์„ ๊ฑธ์–ด ๋™๊ธฐํ™”๋ฅผ ์ˆ˜ํ–‰ํ•˜๋ฏ€๋กœ ์„ฑ๋Šฅ์ด ์ €ํ•˜๋  ์ˆ˜ ์žˆ๋‹ค.

 

4. Double-Checked Locking

synchronized๋กœ ์ธํ•œ ์„ฑ๋Šฅ ์ €ํ•˜๋ฅผ ์ค„์ด๊ธฐ ์œ„ํ•ด ๊ณ ์•ˆ๋œ ๋ฐฉ์‹์ด๋‹ค. ์ธ์Šคํ„ด์Šค๋ฅผ ์ฒ˜์Œ ์ƒ์„ฑํ•  ๋•Œ๋งŒ ๋™๊ธฐํ™”๋ฅผ ์ˆ˜ํ–‰ํ•œ๋‹ค.

public class Singleton {
    private static volatile Singleton instance;

    // private ์ƒ์„ฑ์ž
    private Singleton() {
    }

    // ์ธ์Šคํ„ด์Šค ๋ฐ˜ํ™˜ ๋ฉ”์„œ๋“œ
    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

 

volatile ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด ์ธ์Šคํ„ด์Šค๋ฅผ volatile๋กœ ์„ ์–ธํ•œ ์ด์œ ๋Š”, ์ธ์Šคํ„ด์Šค๊ฐ€ ์ƒ์„ฑ๋˜๋Š” ๊ณผ์ •์„ ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ๊ฐ€ ์ž˜๋ชป ์ฐธ์กฐํ•˜์ง€ ์•Š๋„๋ก ํ•˜๊ธฐ ์œ„ํ•จ์ด๋‹ค. ์ธ์Šคํ„ด์Šค๊ฐ€ ์ƒ์„ฑ๋˜๋Š” ๋™์•ˆ CPU ๋ช…๋ น์–ด๊ฐ€ ์ตœ์ ํ™”๋˜์–ด ์ค‘๊ฐ„ ์ƒํƒœ๋ฅผ ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ๊ฐ€ ๋ณผ ์ˆ˜ ์žˆ๋Š” ๊ฐ€๋Šฅ์„ฑ์„ ๋ฐฉ์ง€ํ•œ๋‹ค.

  • Double-Checked Locking ๋ฐฉ์‹์—์„œ volatile ํ‚ค์›Œ๋“œ๊ฐ€ ์‚ฌ์šฉ๋˜๋Š” ์ด์œ ๋Š” ๊ฐ์ฒด์˜ ์ƒ์„ฑ ๊ณผ์ •์ด ์›์ž์ ์ด์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ณผ์ •์€ ์—ฌ๋Ÿฌ ๋‹จ๊ณ„(๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น -> ์ƒ์„ฑ์ž ํ˜ธ์ถœํ•ด ๊ฐ์ฒด ์ดˆ๊ธฐํ™” -> ๋ณ€์ˆ˜์— ์ฐธ์กฐ ํ• ๋‹น)๋กœ ์ด๋ฃจ์–ด์ง€๋Š”๋ฐ, ์ด ๊ณผ์ •์ด ์ค‘๊ฐ„ ์ƒํƒœ์ผ ๋–„์—๋Š” ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ๊ฐ€ ๊ฐ์ฒด๋ฅผ ์ฐธ์กฐํ•˜๋ฉด ์™„์ „ํžˆ ์ดˆ๊ธฐํ™”๋˜์ง€ ์•Š์€ ๊ฐ์ฒด์— ์ ‘๊ทผํ•˜๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค. volatile ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ด ๊ฐ์ฒด์˜ ์žฌ์ •๋ ฌ(๋ช…๋ นํ™” ์ตœ์ ํ™”) ๋ฌธ์ œ๋ฅผ ๋ฐฉ์ง€ํ•˜๊ณ ,  ๊ฐ์ฒด๊ฐ€ ์™„์ „ํžˆ ์ƒ์„ฑ๋œ ํ›„์— ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ์—์„œ ์ฐธ์กฐํ•˜๋„๋ก ๋ณด์žฅํ•œ๋‹ค.

3๋ฒˆ์˜ getInstance() ๋ฉ”์†Œ๋“œ์— ์ถ”๊ฐ€ํ•œ synchronized๋ฅผ ๋นผ๋ฉด์„œ ์˜ค๋ฒ„ํ—ค๋“œ๋Š” ์ค„์ธ๋‹ค.

 

null ์ฒดํฌ๋ฅผ ๋‘ ๋ฒˆํ•˜๋Š” ์ด์œ  : ๋ถˆํ•„์š”ํ•œ ๋™๊ธฐํ™”๋ฅผ ์ค„์ด๊ณ  ์„ฑ๋Šฅ์„ ์ตœ์ ํ•˜๊ณ  ํ•˜๊ธฐ ์œ„ํ•จ. ์‹ฑ๊ทธํ†ค ๊ฐ์ฒด๊ฐ€ ์ด๋ฏธ ์ƒ์„ฑ๋œ ์ดํ›„์—๋Š” ๋™๊ธฐํ™”์—†์ด ๋น ๋ฅด๊ฒŒ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ๋‹ค.

  • ์ฒซ ๋ฒˆ ์งธ null ์ฒดํฌ์˜ ์—ญํ• 
    • ๋ถˆํ•„์š”ํ•œ ๋™๊ธฐํ™” ๋ฐฉ์ง€ : ์ฒซ ๋ฒˆ์งธ if(instance == null) ์ฒดํฌ๋Š”, ๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ ์ธ์Šคํ„ด์Šค๊ฐ€ ์ด๋ฏธ ์ƒ์„ฑ๋˜์–ด ์žˆ์„ ๋•Œ ๋™๊ธฐํ™” ๋ธ”๋ก์— ๋“ค์–ด๊ฐ€์ง€ ์•Š๋„๋ก ํ•˜๊ธฐ ์œ„ํ•œ ๊ฒƒ์ด๋‹ค. ์ฆ‰, ์ด๋ฏธ ์‹ฑ๊ธ€ํ†ค ๊ฐ์ฒด๊ฐ€ ์ƒ์„ฑ๋œ ์ƒํƒœ์—์„œ๋Š” ์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ๊ฐ€ ๋™๊ธฐํ™” ๋ธ”๋ก์— ์ ‘๊ทผํ•˜์ง€ ์•Š๊ฒŒ ํ•ด ์„ฑ๋Šฅ ์ €ํ•˜๋ฅผ ๋ฐฉ์ง€ํ•œ๋‹ค.
    • ์‹ฑ๊ธ€ํ†ค ๊ฐ์ฒด๊ฐ€ ์ด๋ฏธ ์กด์žฌํ•˜๋Š” ๊ฒฝ์šฐ, ์ด ์กฐ๊ฑด๋ฌธ์—์„œ ๋น ๋ฅด๊ฒŒ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ๋™๊ธฐํ™”๋ฅผ ์ˆ˜ํ–‰ํ•˜์ง€ ์•Š๊ณ ๋„ ๋น ๋ฅธ ์ ‘๊ทผ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.
  • ๋‘ ๋ฒˆ์งธ null ์ฒดํฌ์˜ ์—ญํ• 
    • ์•ˆ์ „ํ•œ ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ ๋ณด์žฅ : ์ฒซ ๋ฒˆ์งธ null ์ฒดํฌ๋ฅผ ํ†ต๊ณผํ•  ํ›„, ๋™๊ธฐํ™” ๋ธ”๋ก์— ๋“ค์–ด๊ฐ”์„ ๋•Œ ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ๊ฐ€ ์ด๋ฏธ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ–ˆ์„ ๊ฐ€๋Šฅ์„ฑ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•œ ๊ฒƒ.
    • ์˜ˆ๋ฅผ ๋“ค์–ด,
      1. ๋‘ ๊ฐœ์˜ ์Šค๋ ˆ๋“œ A์™€ B๊ฐ€ ๋™์‹œ์— ์ฒซ ๋ฒˆ์งธ null ์ฒดํฌ๋ฅผ ํ†ต๊ณผํ–ˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜๋ฉด,
      2. ๋‘ ์Šค๋ ˆ๋“œ๊ฐ€ ๋™๊ธฐํ™” ๋ธ”๋ก์— ์ง„์ž…ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋•Œ ์Šค๋ ˆ๋“œ A๊ฐ€ ๋จผ์ € ๋™๊ธฐํ™” ๋ธ”๋ก์— ์ง„์ž…ํ•ด ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๊ณ 
      3. ๊ทธ ํ›„ ์Šค๋ ˆ๋“œ B๋„ ๋™์ผํ•œ ๋ธ”๋ก ์•ˆ์—์„œ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๋ ค ํ•  ๋•Œ, ๋‘ ๋ฒˆ์งธ if(instance == null) ์ฒดํฌ๋ฅผ ์ˆ˜ํ–‰ํ•ด ์ด๋ฏธ ์ƒ์„ฑ๋œ ์ธ์Šคํ„ด์Šค๊ฐ€ ์žˆ์œผ๋ฉด ๋‹ค์‹œ ์ƒ์„ฑํ•˜์ง€ ์•Š๋„๋ก ํ•œ๋‹ค.

์žฅ์ 

์ธ์Šคํ„ด์Šค๋ฅผ ์ฒ˜์Œ ์ƒ์„ฑํ•  ๋•Œ๋งŒ ๋™๊ธฐํ™”๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์„ฑ๋Šฅ ์ด์Šˆ๋ฅผ ์ค„์ผ ์ˆ˜ ์žˆ๋‹ค.

 

5. ์ •์  ๋‚ด๋ถ€ ํด๋ž˜์Šค Static Inner Class

Lazy Initialization์„ ๋ณด์žฅํ•˜๋ฉด์„œ๋„, JVM์˜ ํด๋ž˜์Šค ๋กœ๋”ฉ ์›์น™์„ ์ด์šฉํ•ด ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์Šค๋ ˆ๋“œ ์•ˆ์ „์„ฑ์„ ํ™•๋ณดํ•˜๋Š” ๋ฐฉ์‹์ด๋‹ค.

public class Singleton {
    // private ์ƒ์„ฑ์ž
    private Singleton() {
    }

    // ์ •์  ๋‚ด๋ถ€ ํด๋ž˜์Šค
    private static class Holder {
        private static final Singleton INSTANCE = new Singleton();
    }

    // ์ธ์Šคํ„ด์Šค ๋ฐ˜ํ™˜ ๋ฉ”์„œ๋“œ
    public static Singleton getInstance() {
        return Holder.INSTANCE;
    }
}

 

์žฅ์ 

ํด๋ž˜์Šค ๋กœ๋”ฉ ์‹œ์ ์— Singleton ํด๋ž˜์Šค๊ฐ€ ์•„๋‹Œ Holder ํด๋ž˜์Šค๊ฐ€ ๋กœ๋“œ๋˜๋ฏ€๋กœ Lazy Initialization์„ ์ง€์›ํ•˜๋ฉฐ, JVM ํด๋ž˜์Šค ๋กœ๋”ฉ ๋งค์ปค๋‹ˆ์ฆ˜์„ ์ด์šฉํ•ด ์Šค๋ ˆ๋“œ ์•ˆ์ „์„ฑ์„ ๋ณด์žฅํ•œ๋‹ค. ์ด ๋ฐฉ์‹์€ ๊ฐ„๊ฒฐํ•˜๋ฉด์„œ๋„ ์„ฑ๋Šฅ ์ €ํ•˜๊ฐ€ ์—†๋Š” ๊ฒƒ์ด ํฐ ์žฅ์ ์ด๋‹ค.

 

๋‚ด๋ถ€ Static ํด๋ž˜์Šค๋ฅผ ์ด์šฉํ•ด ์ฐธ์กฐ๋˜๊ธฐ ์ „๊นŒ์ง€ ๋‚ด๋ถ€ ํด๋ž˜์Šค๋ฅผ ๋กœ๋“œํ•˜์ง€ ์•Š๋Š”๋‹ค.

Static final ์ธ์Šคํ„ด์Šค๋กœ ์‹ฑ๊ธ€ํ„ด ํด๋ž˜์Šค๊ฐ€ ์„ ์–ธ๋˜์–ด, ์ธ์Šคํ„ด์Šค๊ฐ€ ํ•œ ๋ฒˆ๋งŒ ์ดˆ๊ธฐํ™”๋˜๊ณ , ์ดํ›„ ์ ‘๊ทผ ์‹œ ๋™์ผํ•œ ์ธ์Šคํ„ด์Šค๊ฐ€ ๋ฐ˜ํ™˜๋˜๋Š” ๊ฑธ ๋ณด์ฆํ•œ๋‹ค.

  • ์ด ๋ฐฉ์‹์ด Lazy Initialization์„ ์ง€์›ํ•˜๋Š” ์ด์œ 
    1. Lazy Loading ํŠน์„ฑ
      • Holder ํด๋ž˜์Šค๋Š” getInstance() ๋ฉ”์†Œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋  ๋•Œ ์ตœ์ดˆ๋กœ ๋กœ๋“œ๋œ๋‹ค. ์ด๋•Œ Holder ํด๋ž˜์Šค๊ฐ€ ๋กœ๋“œ๋˜๋ฉด์„œ ๊ทธ ์•ˆ์— ์žˆ๋Š” INSTACE๋„ ์ดˆ๊ธฐํ™”๋œ๋‹ค.
      • Singleton ํด๋ž˜์Šค ์ž์ฒด๋Š” ๋กœ๋“œ๋˜๋”๋ผ๋„ ๋‚ด๋ถ€์˜ Holder ํด๋ž˜์Šค๋Š” ์‚ฌ์šฉํ•˜์ง€ ์•Š์œผ๋ฉด ๋กœ๋“œ๋˜์ง€ ์•Š์œผ๋ฏ€๋กœ, INSTANCE๋Š” ํ•„์š”ํ•  ๋•Œ๋งŒ ์ƒ์„ฑ๋œ๋‹ค. ์ด๋ ‡๊ฒŒ Lazy Initialization์ด ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๊ตฌํ˜„๋œ๋‹ค.
    2. JVM ํด๋ž˜์Šค ๋กœ๋”ฉ์˜ ์Šค๋ ˆ๋“œ ์•ˆ์ „์„ฑ
      • JVM์€ ํด๋ž˜์Šค ๋กœ๋”ฉ๊ณผ ์ดˆ๊ธฐํ™” ๊ณผ์ •์ด ์Šค๋ ˆ๋“œ ์•ˆ์ „ํ•˜๋„๋ก ๋ณด์žฅํ•œ๋‹ค. ์ฆ‰, ํด๋ž˜์Šค๊ฐ€ ๋กœ๋“œ๋˜๊ณ  ์ดˆ๊ธฐํ™”๋˜๋Š” ๊ณผ์ •์€ JVM์— ์˜ํ•ด ํ•œ ๋ฒˆ๋งŒ ์ด๋ฃจ์–ด์ง€๋ฉฐ, ์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ๊ฐ€ ๋™์‹œ์— ์ ‘๊ทผํ•˜๋”๋ผ๋„ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š”๋‹ค.
      • ๋”ฐ๋ผ์„œ Holder ํด๋ž˜์Šค๊ฐ€ ๋กœ๋“œ๋  ๋•Œ INSTANCE๊ฐ€ ์ดˆ๊ธฐํ™”๋˜๋ฉด, ์ด ๊ณผ์ •์ด ์Šค๋ ˆ๋“œ ์•ˆ์ „ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ถ”๊ฐ€์ ์ธ ๋™๊ธฐํ™” ์—†์ด๋„ ์•ˆ์ „ํ•˜๊ฒŒ ์‹ฑ๊ธ€ํ†ต ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

 

๋ผ๊ณ  ์จ๋†จ์œผ๋‚˜, ํด๋ž˜์Šค ๋กœ๋“œ ์‹œ์ ์„ ๊ณ ๋ คํ•ด๋ณด๋ฉด, 1๋ฒˆ๊ณผ 5๋ฒˆ์œผ๋กœ ๊ตฌํ˜„ํ•œ ์‹ฑ๊ธ€ํ†ค ๊ฐ์ฒด๋“ค์€ getInstance()๋ฅผ ์ตœ์ดˆ ํ˜ธ์ถœ ์‹œ์— ๋‚ด๋ถ€์ ์œผ๋กœ ๋™์ผํ•˜๊ฒŒ ๋Œ์•„๊ฐ„๋‹ค.

์‹ฑ๊ธ€ํ†ค ๊ฐ์ฒด๋Š” Singleton.getInstance() ์ฝ”๋“œ๋ฅผ ํ•œ ๋ฌถ์Œ์œผ๋กœ ํ˜ธ์ถœํ•ด ์‚ฌ์šฉํ•œ๋‹ค. ํด๋ž˜์Šค ๋กœ๋“œ ์‹œ์ ์€ ํด๋ž˜์Šค๊ฐ€ ์ฒ˜์Œ ์‚ฌ์šฉ๋  ๋•Œ์ด๊ธฐ ๋•Œ๋ฌธ์—, ๋‘ ๋ฐฉ๋ฒ•์œผ๋กœ ์ƒ์„ฑํ•œ Singleton ๊ฐ์ฒด๋“ค์„ ์ตœ์ดˆ๋กœ ํ˜ธ์ถœํ•˜๋Š” Singleton.getInstance() ์ฝ”๋“œ ์‚ฌ์šฉ์‹œ์— 5๋ฒˆ์œผ๋กœ ๊ตฌํ˜„๋œ ์ •์  ๋‚ด๋ถ€ ํด๋ž˜์Šค๋„ ์ด ์‹œ์ ์—์„œ ๋กœ๋“œ๋œ๋‹ค. 5๋ฒˆ์˜ ์žฅ์ ์ด๋ผ๋Š” Lazy Loading์ด ๋”ฑํžˆ ๋“œ๋Ÿฌ๋‚˜์ง€ ์•Š๋Š”๋‹ค. 

 

6. Enum

์ž๋ฐ”์˜ enum์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ์‹ฑ๊ธ€ํ†ค์˜ ํŠน์„ฑ์„ ๊ฐ€์ง€๋ฏ€๋กœ, ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด ๊ตฌํ˜„์‹œ ์ฝ”๋“œ์˜ ๊ฐ„๊ฒฐ์„ฑ, ์ง๋ ฌํ™” ์•ˆ์ „์„ฑ, ๊ทธ๋ฆฌ๊ณ  ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ ํ™˜๊ฒฝ์—์„œ์˜ ์•ˆ์ „์„ฑ์„ ๋ชจ๋‘ ์ œ๊ณตํ•œ๋‹ค.

public enum Singleton {
    INSTANCE;

    // ์›ํ•˜๋Š” ๋ฉ”์„œ๋“œ๋‚˜ ํ•„๋“œ๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    public void someMethod() {
        System.out.println("Enum Singleton Method Called");
    }
}

 

INSTATNCE : ์ด ํ•„๋“œ๊ฐ€ ๋ฐ”๋กœ ์‹ฑ๊ธ€ํ†ค ๊ฐ์ฒด์ด๋‹ค. Singleton.INSTANCE๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ์–ธ์ œ๋‚˜ ๋™์ผํ•œ ์ธ์Šคํ„ด์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

enum์€ JVM์—์„œ ํด๋ž˜์Šค ๋กœ๋”ฉ์„ ์Šค๋ ˆ๋“œ ์•ˆ์ „ํ•˜๊ฒŒ ๋ณด์žฅํ•˜๋ฏ€๋กœ, ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ ํ™˜๊ฒฝ์—์„œ๋„ ์•ˆ์ „ํ•œ ์‹ฑ๊ธ€ํ†ค ๊ฐ์ฒด๋ฅผ ์ œ๊ณตํ•œ๋‹ค.

 

์žฅ์  :

1. ๊ตฌํ˜„์ด ๊ฐ„๊ฒฐํ•˜๋‹ค.

2. ์ง๋ ฌํ™”/์—ญ์ง๋ ฌํ™” ๊ณผ์ •์—์„œ ์‹ฑ๊ธ€ํ†ค์˜ ์œ ์ผ์„ฑ์ด ๊นจ์งˆ ์œ„ํ—˜์ด ์—†๋‹ค.

  • enum์˜ ์ง๋ ฌํ™”/์—ญ์ง๋ ฌํ™” ๊ณผ์ •
    • JVM์˜ ๋ณด์žฅ
      • enum ํƒ€์ž…์€ ์ž๋ฐ” ์–ธ์–ด ์‚ฌ์–‘์— ์˜ํ•ด ๊ณ ์œ ํ•˜๊ฒŒ ๊ด€๋ฆฌ๋œ๋‹ค. ์ฆ‰, ๋ชจ๋“  enum ๊ฐ’์€ JVM์— ์˜ํ•ด ๋‹จ ํ•˜๋‚˜์˜ ์ธ์Šคํ„ด์Šค๋กœ ๋ณด์žฅ๋˜๋ฉฐ, ์ด๋ฅผ ํ†ตํ•ด ์—ญ์ง๋ ฌํ™” ์‹œ์—๋„ ๋™์ผํ•œ ์ธ์Šคํ„ด์Šค๊ฐ€ ๋ฐ˜ํ™˜๋œ๋‹ค.
      • ์ด๋Š” enum์ด ํด๋ž˜์Šค ๋กœ๋”ฉ ์‹œ ์ž๋™์œผ๋กœ JVM ๋‚ด์—์„œ ์ƒ์ˆ˜์ฒ˜๋Ÿผ ๊ด€๋ฆฌ๋˜๊ธฐ ๋–„๋ฌธ์— ๊ฐ€๋Šฅํ•˜๋‹ค.
    • ์ง๋ ฌํ™”์˜ ํŠน๋ณ„ ์ฒ˜๋ฆฌ
      • enum์€ ์ž๋ฐ”์—์„œ ํŠน๋ณ„ํ•œ ๋ฐฉ์‹์œผ๋กœ ์ง๋ ฌํ™”๋˜๊ณ , ์—ญ์ง๋ ฌํ™”๋  ๋•Œ๋„ ๊ทธ ์œ ์ผํ•œ ์ธ์Šคํ„ด์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ์ด๋Š” java.io.Serializable ์ธํ„ฐํŽ˜์ด์Šค์˜ ์ผ๋ฐ˜์ ์ธ ๊ตฌํ˜„๊ณผ๋Š” ๋‹ค๋ฅธ ๋ฐฉ์‹์œผ๋กœ ์ฒ˜๋ฆฌ๋œ๋‹ค.
      • enum์€ ์—ญ ์ง๋ ฌํ™” ์‹œ ์ƒˆ๋กœ์šด ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜์ง€ ์•Š๊ณ , ํ•ญ์ƒ JVM์— ์ €์žฅ๋œ ์‹ฑ๊ธ€ํ†ค ์ธ์Šคํ„ด์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฏ€๋กœ, ์œ ์ผ์„ฑ์ด ์œ ์ง€๋œ๋‹ค.
  • ๋‹ค๋ฅธ ์‹ฑ๊ธ€ํ†ค ๊ฐ์ฒด์—์„œ ์ง๋ ฌํ™”/์—ญ์ง๋ ฌํ™” ๊ณผ์ •์˜ ๋ฌธ์ œ
    • ๋‹ค๋ฅธ ๋ฐฉ์‹์œผ๋กœ ๊ตฌํ˜„ํ•œ ์‹ฑ๊ธ€ํ†ค ๊ฐ์ฒด๋Š” ๊ธฐ๋ณธ์ ์ธ ์ง๋ ฌํ™” ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜๋ฉด ์‹ฑ๊ธ€ํ† ์˜ ์œ ์ผ์„ฑ์ด ๊นจ์งˆ ์ˆ˜ ์žˆ๋‹ค. ๊ทธ ์ด์œ ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.
      • ์ง๋ ฌํ™” ๊ณผ์ •
        • ์ผ๋ฐ˜ ํด๋ž˜์Šค์˜ ๊ฒฝ์šฐ, ์‹ฑ๊ธ€ํ†ค ๊ฐ์ฒด๋ฅผ ์ง๋ ฌํ™”ํ•˜๋ฉด ๊ฐ์ฒด์˜ ์ƒํƒœ๊ฐ€ ๋ฐ”์ดํŠธ ์ŠคํŠธ๋ฆผ์œผ๋กœ ๋ณ€ํ™˜๋˜์–ด ์ €์žฅ๋œ๋‹ค.
      • ์—ญ์ง๋ ฌํ™” ๊ณผ์ •
        • ๊ฐ์ฒด๋ฅผ ์—ญ์ง๋ ฌํ™”ํ•˜๋ฉด, ์ €์žฅ๋œ ๋ฐ”์ดํŠธ ์ŠคํŠธ๋ฆผ์„ ํ†ตํ•ด ์ƒˆ๋กœ์šด ๊ฐ์ฒด ์ธ์Šคํ„ด์Šค๊ฐ€ ์ƒ์„ฑ๋œ๋‹ค. ์ด๋•Œ ๊ธฐ์กด์— ์žˆ๋˜ ์‹ฑ๊ธ€ํ†ค ๊ฐ์ฒด๊ฐ€ ์•„๋‹Œ ์ƒˆ๋กœ์šด ๊ฐ์ฒด๊ฐ€ ๋งŒ๋“ค์–ด์ ธ์„œ ์‹ฑ๊ธ€ํ†ค์˜ ์œ ์ผ์„ฑ์ด ๊นจ์งˆ ์ˆ˜ ์žˆ๋‹ค.
    • ํ•ด๊ฒฐ ๋ฐฉ๋ฒ• : readResolve()
      • ์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด, ์ผ๋ฐ˜์ ์œผ๋กœ readResolve ๋ฉ”์†Œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•ด ์‹ฑ๊ธ€ํ†ค์˜ ์œ ์ผ์„ฑ์„ ์œ ์ง€ํ•œ๋‹ค. ์ด ๋ฉ”์†Œ๋“œ๋Š” ์—ญ์งˆ๋ คํ™”๋œ ๊ฐ์ฒด ๋Œ€์‹  ๊ธฐ์กด์˜ ์‹ฑ๊ธ€ํ†ค ์ธ์Šคํ„ด์Šค๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋„๋ก ํ•œ๋‹ค.
private Object readResolve() throws ObjectStreamException {
    return instance; // ๊ธฐ์กด์˜ ์‹ฑ๊ธ€ํ†ค ์ธ์Šคํ„ด์Šค๋ฅผ ๋ฐ˜ํ™˜
}

 

3. enum์€ ํด๋ž˜์Šค ๋กœ๋”ฉ ์‹œ์ ์—์„œ JVM์— ์˜ํ•ด ์ดˆ๊ธฐํ™”๋˜๋ฉฐ, ์ด ๊ณผ์ •์€ ์Šค๋ ˆ๋“œ ์•ˆ์ „ํ•˜๋ฏ€๋กœ ๋ณ„๋„์˜ ๋™๊ธฐํ™” ์ฒ˜๋ฆฌ๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š๋‹ค.

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

4. enum์€ ๋ฆฌํ”Œ๋ ‰์…˜์„ ์‚ฌ์šฉํ•ด๋„ ์ƒˆ๋กœ์šด ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์—†์–ด์„œ ๋ฆฌํ”Œ๋ ‰์…˜ ๊ณต๊ฒฉ์— ๋Œ€ํ•œ ๋ฐฉ์–ด๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค.

  • enum์ด ๋ฆฌํ”Œ๋ ‰์…˜์„ ํ†ตํ•ด ์ƒˆ๋กœ์šด ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์—†๋Š” ์ด์œ 
    • ๋ฆฌํ”Œ๋ ‰์…˜์„ ํ†ตํ•œ ์ƒ์„ฑ ์ œํ•œ 
      • enum์˜ ์ƒ์„ฑ์ž๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ private์ด๋ฉฐ, ์ž๋ฐ” ๋ฆฌํ”Œ๋ ‰์…˜ API๋ฅผ ํ†ตํ•ด ์ ‘๊ทผํ•˜๋”๋ผ๋„ ์ƒˆ๋กœ์šด ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์—†๊ฒŒ ๋˜์–ด ์žˆ๋‹ค. enum ํƒ€์ž…์€ java.lang.reflect.Constructor์˜ newInstance() ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ, IllegalArgumentException์„ ๋ฐœ์ƒ์‹œ์ผœ ์ƒˆ๋กœ์šด ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ์„ ๋ง‰๋Š”๋‹ค.
    • ์ž๋ฐ” ์–ธ์–ด ์ŠคํŽ™
      • enum์€ ์ƒ์ˆ˜์ฒ˜๋Ÿผ ์‚ฌ์šฉ๋˜๋Š” ํŠน๋ณ„ํ•œ ์œ ํ˜•์„ ํด๋ž˜์Šค์ด๋ฉฐ, ์ด ํŠน์„ฑ์„ ์œ ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ๋ฆฌํ”Œ๋ ‰์…˜์„ ํ†ตํ•œ ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ์ด ์ œํ•œ๋œ๋‹ค. ์ด ์„ค๊ณ„๋Š” enum ์ธ์Šคํ„ด์Šค๊ฐ€ ํ•ญ์ƒ ์œ ์ผํ•˜๋ฉฐ, ์‹ฑ๊ธ€ํ†ค์˜ ํŠน์ •์ด ์œ ์ง€๋˜๋„๋ก ๋ณด์žฅํ•˜๋Š” ๋ฐ ๋ชฉ์ ์ด ์žˆ๋‹ค.
  • ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์œผ๋กœ ๋งŒ๋“  ์‹ฑ๊ธ€ํ†ค ๊ฐ์ฒด์—์„œ ๋ฆฌํ”Œ๋ ‰์…˜ ๊ณต๊ฒฉ์„ ๋ฐฉ์–ดํ•˜๋Š” ๋ฐฉ๋ฒ•
    • ๊ธฐ์กด ์ธ์Šคํ„ด์Šค๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ์— ์˜ˆ์™ธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚จ๋‹ค.
      • ๋ฆฌํ”Œ๋ ‰์…˜์„ ํ†ตํ•œ ์ƒ์„ฑ ๋ฐฉ์ง€๋ฅผ ์œ„ํ•ด, ์ƒ์„ฑ์ž ๋‚ด๋ถ€์—์„œ ๊ธฐ์กด ์ธ์Šคํ„ด์Šค ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•˜๊ณ  ์ด๋ฏธ ์ธ์Šคํ„ด์Šค๊ฐ€ ์กด์žฌํ•œ๋‹ค๋ฉด ์˜ˆ์™ธ๋ฅผ ๋˜์ง€๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๋ฆฌํ”Œ๋ ‰์…˜์œผ๋กœ ์ƒ์„ฑ์ž๋ฅผ ํ˜ธ์ถœํ•˜๋”๋ผ๋„ ๊ธฐ์กด ์ธ์Šคํ„ด์Šค๊ฐ€ ์žˆ์œผ๋ฉด ์ƒˆ๋กœ์šด ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์—†๋‹ค.
public class Singleton {
    private static Singleton instance;

    // private ์ƒ์„ฑ์ž
    private Singleton() {
        if (instance != null) {
            throw new RuntimeException("Use getInstance() method to create");
        }
    }

    // ์ธ์Šคํ„ด์Šค ๋ฐ˜ํ™˜ ๋ฉ”์„œ๋“œ
    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

 

๋‹จ์  : enum์€ ์ž๋ฐ”์—์„œ ํด๋ž˜์Šค ์ƒ์†์„ ์ง€์›ํ•˜์ง€ ์•Š์•„์„œ ์‹ฑ๊ธ€ํ†ค ํด๋ž˜์Šค๋ฅผ ์ƒ์†ํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š” ์ ํ•ฉํ•˜์ง€ ์•Š๋‹ค. enum์€ ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ ๋ฐฉ์‹์ด ๊ณ ์ •์ ์ด๋ผ์„œ, ์ดˆ๊ธฐํ™” ๊ณผ์ •์—์„œ ํŠน์ • ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๋ฐ›๋Š” ๋“ฑ ๋” ์œ ์—ฐํ•œ ์ดˆ๊ธฐํ™”๋ฅผ ์›ํ•  ๊ฒฝ์šฐ์— ์‚ฌ์šฉํ•˜๊ธฐ ์–ด๋ ต๋‹ค.

 

์•ˆ๋“œ๋กœ์ด๋“œ ํ™˜๊ฒฝ์—์„œ๋Š” ์–ด๋–ค ๋ฐฉ์‹์ด ์ ํ•ฉํ• ๊นŒ?

1์œ„. ์ •์  ๋‚ด๋ถ€ ํด๋ž˜์Šค(Static Inner Class) ๋ฐฉ์‹

 

๐Ÿค” ์™œ ์ •์  ๋‚ด๋ถ€ ํด๋ž˜์Šค(Static Inner Class) ๋ฐฉ์‹์œผ๋กœ ์‹ฑ๊ธ€ํ„ด ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์ด ์•ˆ๋“œ๋กœ์ด๋“œ ํ™˜๊ฒฝ์—์„œ ๋” ์ ํ•ฉํ• ๊นŒ?

1. ์„ฑ๋Šฅ ์ตœ์ ํ™”

์ •์  ๋‚ด๋ถ€ ํด๋ž˜์Šค ๋ฐฉ์‹์€ ํด๋ž˜์Šค ๋กœ๋”ฉ ์‹œ์ ์—์„œ JVM์— ์˜ํ•ด ์Šค๋ ˆ๋“œ ์•ˆ์ „์„ฑ์„ ๋ณด์žฅ๋ฐ›๊ณ , ๋™๊ธฐํ™” ๋ธ”๋ก์ด ํ•„์š”ํ•˜์ง€ ์•Š์•„ ๋ถˆํ•„์š”ํ•œ ์„ฑ๋Šฅ ์ €ํ•˜๋ฅผ ํ”ผํ•  ์ˆ˜ ์žˆ๋‹ค.

2. Lazy Initialization

์ธ์Šคํ„ด์Šค๊ฐ€ ํ•„์š”ํ•  ๋•Œ๊นŒ์ง€ ์ดˆ๊ธฐํ™”๋˜์ง€ ์•Š์•„ ๋ฉ”๋ชจ๋ฆฌ ์ž์›์„ ํšจ์œจ์ ์œผ๋กœ ์‚ฌ์šฉํ•œ๋‹ค. ์ด๋Š” ๋ฉ”๋ชจ๋ฆฌ ์ œ์•ฝ์ด ์žˆ๋Š” ์•ˆ๋“œ๋กœ์ด๋“œ ํ™˜๊ฒฝ์—์„œ ์ค‘์š”ํ•˜๋‹ค.

3. ์•ˆ์ „์„ฑ

JVM์ด ํด๋ž˜์Šค ๋กœ๋”ฉ๊ณผ ์ดˆ๊ธฐํ™”๋ฅผ ์Šค๋ ˆ๋“œ ์•ˆ์ „ํ•˜๊ฒŒ ์ฒ˜๋ฆฌํ•˜๋ฏ€๋กœ ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ ํ™˜๊ฒฝ์—์„œ๋„ ์•ˆ์ „ํ•˜๊ฒŒ ์‹ฑ๊ธ€ํ†ค ์ธ์Šคํ„ด์Šค๋ฅผ ๋ณด์žฅํ•œ๋‹ค.

 

2์œ„. Enum ๋ฐฉ์‹

์žฅ์ 

  • ๊ตฌํ˜„์˜ ๊ฐ„๊ฒฐ์„ฑ: enum์€ ๊ฐ„๊ฒฐํ•˜๊ฒŒ ์‹ฑ๊ธ€ํ†ค์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์ž‡์œผ๋ฉฐ, ์ถ”๊ฐ€์ ์ธ ์ฝ”๋“œ ์—†์ด JVM์ด ์Šค๋ ˆ๋“œ ์•ˆ์ „์„ฑ๊ณผ ์ง๋ ฌํ™” ์•ˆ์ „์„ฑ์„ ๋ณด์žฅํ•œ๋‹ค.
  • ์ง๋ ฌ๊ณผ ์•ˆ์ „์„ฑ : ์•ˆ๋“œ๋กœ์ด๋“œ์—์„œ ์ง๋ ฌํ™”๋œ ๊ฐ์ฒด๋ฅผ ๋ณต๊ตฌํ•  ๋•Œ enum ๋ฐฉ์‹์€ ๋ณ„๋„์˜ ์ฒ˜๋ฆฌ๊ฐ€ ํ•„์š” ์—†์œผ๋ฉฐ, ์•ˆ์ „ํ•˜๋‹ค.
  • ๋ฆฌํ”Œ๋ ‰์…˜ ๋ฐฉ์–ด :๋ฆฌํ”Œ๋ ‰์…˜์„ ํ†ตํ•ด ๊ฐ์ฒด ์ƒ์„œ์ด ๋ถˆ๊ฐ€๋Šฅํ•ด, ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์— ๋น„ํ•ด ๋” ์•ˆ์ „ํ•˜๋‹ค.

๋‹จ์ 

  • ์œ ์—ฐ์„ฑ ๋ถ€์กฑ : enum์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ƒ์†์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๊ณ , ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ํ†ตํ•ด ์ดˆ๊ธฐํ™”ํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š” ์ œํ•œ์ด ์žˆ๋‹ค. Java์˜ ํŠน์ˆ˜ํ•œ ๋ฐฉ์‹์ด๊ธฐ ๋•Œ๋ฌธ์— ๋‹ค๋ฅธ JVM ์–ธ์–ด๋‚˜ ํŠน์ˆ˜ํ•œ ์ดˆ๊ธฐํ™”๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ์—๋Š” ์‚ฌ์šฉ์ด ์–ด๋ ค์šธ ์ˆ˜ ์žˆ๋‹ค.

โญDouble-Checked Locking + volatile ํ‚ค์›Œ๋“œ ์‚ฌ์šฉโญ

์•ˆ๋“œ๋กœ์ด๋“œ์—์„œ๋Š” ์‹ฑ๊ธ€ํ†ค ์ƒ์„ฑ์‹œ Context๋ฅผ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๊ฐ€์ ธ์™€์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ๋“ค์ด ๊ฝค ์žˆ๋‹ค. getInstance()์‹œ ํŒŒ๋ผ๋ฏธํ„ฐ๋“ค์„ ๋ฐ›์•„์˜ฌ ์ˆ˜ ์—†๋Š” ์ƒ์„ฑ ํŒจํ„ด์€ ์•ˆ๋“œ๋กœ์ด๋“œ์—์„œ ์ ํ•ฉํ•˜์ง€ ์•Š๋‹ค.

๋˜ํ•œ Double-Checked Locking์€ ์„ฑ๋Šฅ๋„ ์ข‹๋‹ค.

 

๊ทธ๋Ÿฌ๋‚˜ ์š”์ฆ˜์—๋Š” ์•ˆ๋“œ๋กœ์ด๋“œ์—์„œ ์‹ฑ๊ธ€ํ†ค ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค. ๋Œ€์‹  Hilt๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

 

(๋‚ด์šฉ ์ถ”๊ฐ€ ์˜ˆ์ •)