JiwonDev

2-3 Singleton (์‹ฑ๊ธ€ํ†ค ํŒจํ„ด)

by JiwonDev

# ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด

ํ”„๋กœ์„ธ์Šค์— ๊ฐ์ฒด์˜ ์ธ์Šคํ„ด์Šค๊ฐ€ ๋‹จ ํ•˜๋‚˜๋งŒ ์กด์žฌํ•˜๋„๋ก ๋งŒ๋“œ๋Š” ํŒจํ„ด.

โญ• Static ๋ฉ”๋ชจ๋ฆฌ ์˜์—ญ์— ๊ฐ์ฒด๋ฅผ ํ•˜๋‚˜๋งŒ ์ƒ์„ฑ, ์žฌ์‚ฌ์šฉํ•จ์œผ๋กœ์„œ ๋ฉ”๋ชจ๋ฆฌ ๋‚ญ๋น„๋ฅผ ๋ฐฉ์ง€ํ•œ๋‹ค.

โญ• ๊ฐ์ฒด๋ฅผ ์ƒˆ๋กœ ์ƒ์„ฑํ•˜์ง€ ์•Š๊ณ , ๊ธฐ์กด์˜ ๊ฐ์ฒด๋ฅผ ์žฌ์‚ฌ์šฉํ•จ์œผ๋กœ์„œ ๋กœ๋”ฉ ์‹œ๊ฐ„์„ ์ค„์—ฌ ์„ฑ๋Šฅ์„ ํ–ฅ์ƒ์‹œํ‚จ๋‹ค.

โŒ (์•ˆํ‹ฐ ํŒจํ„ด) ์‹ฑ๊ธ€ํ†ค ๊ฐ์ฒด๊ฐ€ ์ƒํƒœ ๊ฐ’์„ ๊ฐ€์งˆ ๊ฒฝ์šฐ ์ •๋ง ์ฐพ๊ธฐ ํž˜๋“  Side-Effect์™€ ์žฅ์• ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.

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

 

# ์‹ฑ๊ธ€ํ†ค ํŒจํ„ด์˜ ๊ตฌํ˜„

@1. ์ฆ‰์‹œ ๋กœ๋”ฉ (Eager initialization)

โžก ๊ฐ€์žฅ ๋‹จ์ˆœํ•œ ๋ฐฉ๋ฒ•์ด๋‹ค. private static final ์„ ์‚ฌ์šฉํ•ด์„œ, ํด๋ž˜์Šค๊ฐ€ JVM์— ์ฝํ˜€์งˆ ๋•Œ ๊ฐ์ฒด๊ฐ€ ๋งŒ๋“ค์–ด์ง€๋„๋ก ํ•œ๋‹ค.

โŒ ํด๋ž˜์Šค๊ฐ€ ์ƒ์„ฑ๋˜๋Š” ์‹œ์ ์— ์–ด๋– ํ•œ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ๋„ ํ•  ์ˆ˜ ์—†๋‹ค. ๋‚œ๊ฐํ•˜๋‹ค.

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

public class Singleton {

    private static final Singleton instance = new Singleton();

    // ์ƒ์„ฑ์ž๋ฅผ ์‚ฌ์šฉ ๋ชปํ•˜๊ฒŒ ๋ง‰์•„๋ฒ„๋ฆฐ๋‹ค.
    private Singleton() {}

    // ํ•„์š”ํ•˜๋ฉด getInstance()๋ฅผ ์ด์šฉํ•˜์—ฌ ๊ฐ€์ ธ์˜จ๋‹ค.
    public static Singleton getInstance() {
        return instance;
    }
}

 

@2. ์ง€์—ฐ ๋กœ๋”ฉ (Lazy initialization)

โžก ๊ทธ๋Ÿฌ๋ฉด ์‚ฌ์šฉํ•˜๋Š” ์‹œ์ ์— ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๋ฉด ๋˜๋Š”๊ฑฐ ์•„๋‹๊นŒ?

โŒ ๋ฉ€ํ‹ฐ ์Šค๋ ˆ๋“œ์—์„œ ๋™๊ธฐํ™” ๋˜์ง€ ์•Š๋Š”๋‹ค. ์ฆ‰ ๋™์‹œ์— getInstance()๋ฅผ ํ˜ธ์ถœํ•ด์„œ ์ธ์Šคํ„ด์Šค๊ฐ€ 2๊ฐœ๊ฐ€ ๋งŒ๋“ค์–ด ์งˆ ์ˆ˜ ์žˆ๋‹ค.

public class LazyInitialization {

    private static LazyInitialization instance;
    
    private LazyInitialization() {}

    public static LazyInitialization getInstance() {
        if (instance == null) { // getInstance()์˜ ํ˜ธ์ถœ ์‹œ์ ์— ์ƒ์„ฑํ•จ.
            instance = new LazyInitialization();
        }
        return instance;
    }
}

 

@3. Thread Safe, Double checked Locking

โžก ์•„ ๋ฉ€ํ‹ฐ ์Šค๋ ˆ๋“œ์•ผ ๋ญ, synchronzied ๋ถ™์ด๋ฉด ๋˜๋Š”๊ฑฐ์ž–์•„?

โŒ getInstance()๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ ๋งˆ๋‹ค synchronzied ๋•Œ๋ฌธ์— ์Šค๋ ˆ๋“œ๊ฐ€ ๋ธ”๋ก๋œ๋‹ค. ์„ฑ๋Šฅ์ด ํฌ๊ฒŒ ๋–จ์–ด์ง„๋‹ค.

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

โžก ์•„๋‹ˆ ๋งค๋ฒˆ ๋ธ”๋กํ•œ๋‹ค๋Š”๊ฒŒ ์•„๋‹ˆ๋ผ ์กฐ๊ฑด๋ฌธ ๋‹ฌ์•„์„œ ์ฒซ ์ƒ์„ฑ๋•Œ๋งŒ synchronzied๋ฅผ ํ•˜์ž๊ตฌ!

โŒ if (null) ์ผ ๋•Œ๋งŒ ์Šค๋ ˆ๋“œ ๋ธ”๋ก์„ ํ•œ๋‹ค๊ณ  ํ•œ๋“ค ๋‚ด๋ถ€์—์„œ ๋น„๊ต๋ฅผ 2๋ฒˆ (Double Check) ํ•ด์ค˜์•ผํ•˜๊ณ  ์„ฑ๋Šฅ๋„ ์—ฌ์ „ํžˆ ์•ˆ์ข‹๋‹ค.

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

 

 

@4. Lazy Holder ๋ฐฉ๋ฒ• (Bill Pugh's Singleton Implementation)

๋ฏธ๊ตญ ๋ฉ”๋ฆด๋žœ๋“œ ๋Œ€ํ•™ ์—ฐ๊ตฌ์›์ธ Bill pugh๊ฐ€ ์ œ์•ˆํ•œ ๋ฐฉ๋ฒ•์ด๋‹ค.

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

public class Singleton {
 
    private Singleton(){}
    
    // ๊ฐ์ฒด ์ƒ์„ฑ์€ ๋‚ด๋ถ€ํด๋ž˜์Šค(Lazyholder)์—์„œ static์œผ๋กœ ๋งŒ๋“ ๋‹ค.
    private static class LazyHolder{
        private static final Singleton INSTANCE = new Singleton();
    }
    
    public static Singleton getInstance(){
        return LazyHolder.INSTANCE; // ์™ธ๋ถ€ ํด๋ž˜์Šค์—์„œ ์‚ฌ์šฉํ•œ๋‹ค.
    }
}

์–ด? ์ด๋ ‡๊ฒŒํ•˜๋ฉด @2. ์™€ ๊ฐ™์€๊ฑฐ ์•„๋‹Œ๊ฐ€ ์‹ถ์ง€๋งŒ JVM์˜ ๋™์ž‘๊ณผ์ •์„ ์ดํ•ดํ•˜๋ฉด ํฐ ์ฐจ์ด๊ฐ€ ์žˆ์Œ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

  • ์ž๋ฐ”์˜ Static์˜์—ญ์€ JVM์˜ ํด๋ž˜์Šค๋กœ๋”๊ฐ€ [ .Class ] ๋ฅผ ์ฝ์„ ๋•Œ ์ƒ์„ฑ๋˜๊ณ  ์ดˆ๊ธฐํ™” ๋œ๋‹ค.
  • JVM์˜ ํด๋ž˜์Šค๋กœ๋”๋Š” Lazyํ•˜๊ฒŒ ๋™์ž‘ํ•œ๋‹ค. ์ฆ‰ ์‹ฌ๋ณผ๋ฆญ ์ฐธ์กฐ๊ฐ’๋งŒ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค๊ฐ€, ์‚ฌ์šฉ๋˜๋Š” ์‹œ์ ์— ํด๋ž˜์Šค๋ฅผ ์ฝ๋Š”๋‹ค.
  • [@4. LazyHolder] ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์™ธ๋ถ€ํด๋ž˜์Šค๋Š” ๋ฐ”๋กœ ์ฝํžˆ์ง€๋งŒ ๋‚ด๋ถ€ ํด๋ž˜์Šค๋Š” ์‚ฌ์šฉํ•˜๋Š” ์‹œ์ ๊นŒ์ง€ ๋กœ๋”ฉ์ด ๋Šฆ์ถฐ์ง„๋‹ค.
    โญ• JVM์˜ ์ตœ์ ํ™”์— ๋”ฐ๋ผ ๋‹ค๋ฅด๊ฒ ์ง€๋งŒ, ๋Œ€๋ถ€๋ถ„ ์‚ฌ์šฉํ•˜๊ธฐ ์ง์ „๊นŒ์ง€ ๊ฐ์ฒด ์ƒ์„ฑ์„ ๋Šฆ์ถœ ์ˆ˜ ์žˆ๋‹ค.
    โญ• ๊ฒŒ๋‹ค๊ฐ€ static์„ ์ด์šฉํ•œ ์ดˆ๊ธฐํ™”์ด๊ธฐ์— ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ์— ์•ˆ์ „ํ•˜๊ณ , ๋‚ด๋ถ€ ํด๋ž˜์Šค์—์„œ ์˜ˆ์™ธ์ฒ˜๋ฆฌ๋„ ๊ฐ€๋Šฅํ•˜๋‹ค.
// ์ฐธ์กฐ ๊ฐ’๋งŒ ๊ฐ€์ง€๊ณ  ์žˆ์„ ๋ฟ, ์•„์ง ๋‚ด๋ถ€ ํด๋ž˜์Šค๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•˜๋‹ค.
var mySingleton = Singleton.getInstance(); // ์ฆ‰ ์•„์ง ๊นŒ์ง€ ๋‚ด๋ถ€ ํด๋ž˜์Šค๋Š” ์ฝํ˜€์ง€์ง€ ์•Š์•˜์Œ.

/* ... other code ... */

mySingleton.method() // ์ด ์‹œ์ ์— LazyHolder๊ฐ€ ์ฝํ˜€์ง€๊ณ , Static์˜์—ญ์ด ์ดˆ๊ธฐํ™” ๋œ๋‹ค.

์ƒ์„ฑ๋œ ๋ฐ”์ดํŠธ์ฝ”๋“œ์˜ ๋ชจ์Šต. Methodref[ Singleton.getInstance() ]๋งŒ ๊ฐ€์ง€๊ณ  ์žˆ์„ ๋ฟ, ์‚ฌ์šฉํ•˜๊ธฐ ์ „๊นŒ์ง€ ๋‚ด๋ถ€ ํด๋ž˜์Šค๋ฅผ ์ฝ์ง€ ์•Š๋Š”๋‹ค.

 


@5. ๋ฆฌํ”Œ๋ ‰์…˜ ๋ฐฉ์–ด - Enum

์‹ค์ œ ์„œ๋น„์Šค์—์„œ ๊ฐ€์žฅ ๋งŽ์ด ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์€ @4.์ด๋‹ค. 

๋‹ค๋งŒ [@1~@4]๋Š” ์ „๋ถ€ ์ž๋ฐ”์˜ ๋ฆฌํ”Œ๋ ‰์…˜ (๋ฐ”์ดํŠธ์ฝ”๋“œ ์กฐ์ž‘)์„ ์‚ฌ์šฉํ•˜๋Š” ์„œ๋น„์Šค๋Š” ๊ฐœ๋ฐœ์ž์˜ ์‹ค์ˆ˜๋กœ ์‹ฑ๊ธ€ํ†ค์ด ๊นจ์งˆ ์ˆ˜ ์žˆ๋‹ค๋Š” ์œ„ํ—˜์„ฑ์ด ์žˆ๋Š”๋ฐ, Enum์„ ์‚ฌ์šฉํ•˜๋ฉด ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค. โžก ํ•˜์ง€๋งŒ ์„ฑ๋Šฅ์ด ๊ตฌ๋ ค์„œ ์ž˜ ์•ˆ์“ด๋‹ค.

public enum EnumInitialization {
	INSTANCE;
	static String test = "";
	public static EnumInitialization getInstance() {
		test = "test";
		return INSTANCE;
	}
}
// ๋ฆฌํ”Œ๋ ‰์…˜(๋ฐ”์ดํŠธ์ฝ”๋“œ ์กฐ์ž‘)๊นŒ์ง€ ์‚ฌ์šฉํ•˜๋Š” ์„œ๋น„์Šค๋ผ๋ฉด, ์ด๋ ‡๊ฒŒ ํ•ด๋ฒ„๋ฆด ์œ„ํ—˜์ด ์žˆ๊ธดํ•˜๋‹ค.
public class UsingReflectionToDestroySingleton {
	
	public static void main (String[] args) {
		EagerInitialization instance = EagerInitialization.getInstance();
		EagerInitialization instance2 = null;
		
		try {
			Constructor[] constructors = EagerInitialization.class.getDeclaredConstructors();
			for ( Constructor constructor : constructors ) {
				constructor.setAccessible(true);
				instance2 = (EagerInitialization)constructor.newInstance();
			}
		} catch (Exception e) {
			
		}
		
		System.out.println(instance.hashCode());
		System.out.println(instance2.hashCode());
		
	}
}

 

๋ธ”๋กœ๊ทธ์˜ ์ •๋ณด

JiwonDev

JiwonDev

ํ™œ๋™ํ•˜๊ธฐ