# [λ””μžμΈ νŒ¨ν„΄] 생성 νŒ¨ν„΄ - 싱글톀 νŒ¨ν„΄
Study Repository

[λ””μžμΈ νŒ¨ν„΄] 생성 νŒ¨ν„΄ - 싱글톀 νŒ¨ν„΄

by rlaehddnd0422

싱글톀 νŒ¨ν„΄μ΄λž€?

싱글톀

  • ν•˜λ‚˜μ˜ 클래슀λ₯Ό 기반으둜 μ—¬λŸ¬κ°œμ˜ μΈμŠ€ν„΄μŠ€λ₯Ό λ§Œλ“€ 수 μžˆμ§€λ§Œ, κ·Έλ ‡κ²Œ ν•˜μ§€ μ•Šκ³  ν•˜λ‚˜μ˜ μΈμŠ€ν„΄μŠ€λ§Œ λ§Œλ“€μ–΄ μ‚¬μš©ν•˜λŠ” νŒ¨ν„΄.
  • 일반적으둜 λ°μ΄ν„°λ² μ΄μŠ€ μ—°κ²° λͺ¨λ“ˆμ—μ„œ μ‚¬μš©ν•œλ‹€κ³  보면 되겠음.

 

싱글톀 νŒ¨ν„΄ μ‚¬μš© 이유

  1. λ°μ΄ν„°λ² μ΄μ…˜ 컀λ„₯μ…˜ ν’€κ³Ό 같이 ν•˜λ‚˜μ˜ μΈμŠ€ν„΄μŠ€λ§Œ λ§Œλ“€μ–΄ 두고 이 μΈμŠ€ν„΄μŠ€λ₯Ό μž¬ν™œμš©ν•˜μ—¬ ν•„μš”λ‘œ ν•˜λŠ” μž‘μ—…λ“€μ„ μˆ˜ν–‰ν•  수 μžˆλŠ” κ²½μš°μ™€ 같이, μΈμŠ€ν„΄μŠ€λ₯Ό λΆˆν•„μš”ν•˜κ²Œ μ—¬λŸ¬κ°œ λ§Œλ“€ ν•„μš”κ°€ 없을 λ•Œ μ‹±κΈ€ν†€μœΌλ‘œ κ΄€λ¦¬ν•˜μ—¬ λΆˆν•„μš”ν•œ μžμ› μ‚¬μš©μ„ 막기 μœ„ν•΄.

 

싱글톀 νŒ¨ν„΄ 생성 방법

0. 기본적인 방식

  • 싱글톀 νŒ¨ν„΄μ„ μ μš©ν•˜κΈ° μœ„ν•΄μ„œλŠ” 두 개 μ΄μƒμ˜ μΈμŠ€ν„΄μŠ€λ₯Ό λ§Œλ“œλŠ” 것을 막아야 ν•˜κΈ° λ•Œλ¬Έμ— μš°μ„ μ μœΌλ‘œ 객체 생성을 μœ„ν•œ new ν‚€μ›Œλ“œμ— μ œμ•½μ‘°κ±΄μ„ κ±Έμ–΄μ€˜μ•Ό ν•˜κ³ , λ§Œλ“€μ–΄μ§„ 단일 객체λ₯Ό λ°˜ν™˜ν•  수 μžˆλŠ” λ©”μ†Œλ“œκ°€ ν•„μš”ν•©λ‹ˆλ‹€.
public class Main {  

    public static void main(String[] args) {  
        Singleton singleton1 = Singleton.getInstance();  
        Singleton singleton2 = Singleton.getInstance();  

        System.out.println(singleton1 == singleton2); // True  
    }  

    static class Singleton {  
        private static final Singleton INSTANCE;  // static μ˜μ—­μ— 미리 ν•˜λ‚˜ λ§Œλ“€μ–΄ 놓은 ν›„, 객체 생성을 getIntance()둜 ν˜ΈμΆœν•˜μ—¬, 항상 같은 μΈμŠ€ν„΄μŠ€λ₯Ό λ¦¬ν„΄ν•˜λ„λ‘ μ„€μ •

        public static Singleton getInstance() {  
            if(INTANCE == null) {
                INSTANCE = new SingleTon();
            }
            return Singleton.INSTANCE;  
        }  

        // μƒμ„±μžλ₯Ό 톡해 μΈμŠ€ν„΄μŠ€λ₯Ό λ§Œλ“œλŠ” 것을 막아주기
        private Singleton{}(
            // λ‚΄λΆ€μ μœΌλ‘œ ν˜ΈμΆœν•˜λŠ” 경우 μ˜ˆμ™Έλ₯Ό 던져 λ‚΄λΆ€μ—μ„œλ„ μƒˆλ‘œμš΄ μΈμŠ€ν„΄μŠ€λ₯Ό λ§Œλ“€μ§€ λͺ»ν•˜λ„둝 μ„€μ •.
            throw new AssertionError();
        )
    }  
}
  • ν•˜μ§€λ§Œ 이 λ°©μ‹μ˜ 경우 Thread Safe ν•˜μ§€ μ•Šλ‹€λŠ” 치λͺ…적인 단점이 있음.
    public static Singleton getInstance() {  
            // Thread A와 Thread Bμ—μ„œ λ™μ‹œμ— getInstance()λ₯Ό ν˜ΈμΆœν•˜κ²Œ 되면 if 쑰건뢄기문이 A와 Bμ—μ„œ λͺ¨λ‘ ν†΅κ³Όν•˜λŠ” 경우 SingleTon이 κΉ¨μ§€κ²Œ 됨.
            if(INTANCE == null) {
                INSTANCE = new SingleTon();
            }
            return Singleton.INSTANCE;  
    }  
  • μœ„ μ½”λ“œμ—μ„œ μ—¬λŸ¬ μŠ€λ ˆλ“œκ°€ λ™μ‹œμ— getInstance()λ₯Ό λ™μ‹œμ— ν˜ΈμΆœν•˜λŠ” 경우 Singleton μΈμŠ€ν„΄μŠ€κ°€ 두 개 μƒμ„±λ˜μ–΄ 싱글톀 νŒ¨ν„΄μ΄ 깨질 μš°λ €κ°€ 있음.

Thread Safeν•œ 싱글톀 νŒ¨ν„΄ κ΅¬ν˜„ 방법에 λŒ€ν•΄ μ•Œμ•„λ΄…μ‹œλ‹€.

 

1. static + μ€‘μ²©ν΄λž˜μŠ€(홀더) 방식

public class Singleton {

    private Singleton() {
    }

    private static class SingletonHolder {
        private static final Singleton SINGLETON_OBJECT = new Singleton();
    }

    public static Singleton getInstance() {
        return SingletonHolder.SINGLETON_OBJECT;
    }
}
  • μ• ν”Œλ¦¬μΌ€μ΄μ…˜ λ‹Ή 단 ν•˜λ‚˜ + SingletonHoderλ₯Ό μ‹€μ œ μ‚¬μš©ν•  λ•ŒκΉŒμ§€ μ΄ˆκΈ°ν™”λ₯Ό λ―Έλ£Έ.
  • JVM의 클래슀 λ‘œλ”μ— μ˜ν•΄ λ‘œλ“œλ  λ•Œ λ‚΄λΆ€μ μœΌλ‘œ μ‹€ν–‰λ˜μ–΄ 생성됨.
  • 정적 μ΄ˆκΈ°ν™”λ‘œ μƒμ„±λ˜λ―€λ‘œ Thread Safeν•˜λ‹€λŠ” μž₯점.
    • Thread Safe : μ—¬λŸ¬ μŠ€λ ˆλ“œμ—μ„œ getInstance()λ₯Ό ν˜ΈμΆœν•΄λ„ 단 ν•˜λ‚˜μ˜ μΈμŠ€ν„΄μŠ€λ§Œ 리턴.

 

2. Eager init 방식

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

    private Singleton() {
    }

    public static synchronized Singleton getInstance() {
        return SINGLETON_OBJECT;
    }
}
  • 미리 static μ˜μ—­μ— 싱글톀 μΈμŠ€ν„΄μŠ€λ₯Ό μƒμ„±ν•΄λ‘λŠ” 방식.
  • λ§Œμ•½ 생성 λΉ„μš©μ΄ 크고, μΈμŠ€ν„΄μŠ€λ₯Ό μ‚¬μš©ν•˜μ§€ μ•ŠλŠ”λ‹€λ©΄ λ©”λͺ¨λ¦¬ λ‚­λΉ„μ˜ μš°λ €κ°€ 있음.
  • μΆ”κ°€λ‘œ 생성과 λ™μ‹œμ— final ν‚€μ›Œλ“œλ₯Ό 톡해 λΆˆλ³€μ„±μ„ 보μž₯해쀄 수 있음.

 

3. Synchronized lazy init 방식

static class Singleton {  
    private static Singleton singletonObject;  

    private Singleton() {  
    }  

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

        return singletonObject;  
    }  
}
  • λ‹¨μˆœνžˆ synchronized ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•˜μ—¬ getInstance() λ©”μ†Œλ“œμ— ν•˜λ‚˜μ˜ μŠ€λ ˆλ“œλ§Œμ΄ μ ‘κ·Όν• μˆ˜ μžˆλ„λ‘ ν•˜κ²Œ ν•˜λŠ” 방법.
  • μ—¬λŸ¬ μŠ€λ ˆλ“œκ°€ λ™μ‹œμ— μ ‘κ·Όν•˜κ²Œ 되면 동기화 μž‘μ—…μ΄ 이루어지기 λ•Œλ¬Έμ— μ„±λŠ₯μ €ν•˜ λ°œμƒν•  수 있음.

 

4. double check locking 방식

  • volatile ν‚€μ›Œλ“œμ™€ 더블 체크λ₯Ό ν†΅ν•œ synchronized ν‚€μ›Œλ“œλ₯Ό ν™œμš©ν•˜μ—¬ μ΄ˆκΈ°ν™” ν•  λ•Œλ§Œ 동기화 μž‘μ—…μ„ μˆ˜ν–‰ν•˜λŠ” 방법.
  • volatile keywordλŠ” Java λ³€μˆ˜λ₯Ό Main Memory에 μ €μž₯ν•˜κ² λ‹€λΌλŠ” 것을 λͺ…μ‹œν•˜λŠ” ν‚€μ›Œλ“œ
  • μ•žμ„  synchronized lazy init 방식 처럼 getInstance()λ₯Ό ν˜ΈμΆœν•  λ•Œλ§ˆλ‹€ 동기화 μž‘μ—…μ— κ±Έλ¦¬λŠ” 것이 μ•„λ‹ˆλΌ, "졜초" μ΄ˆκΈ°ν™” μ‹œμ—λ§Œ 동기화 μž‘μ—… μˆ˜ν–‰.
  • JVM 버전이 1.5 이상인 κ²½μš°μ—λ§Œ 적용 κ°€λŠ₯
public class Singleton {
    // volatile ν‚€μ›Œλ“œ μ‚¬μš©
    private static volatile Singleton singletonObject;

    private Singleton() {
    }

    public static Singleton getInstance() {
        if (singletonObject == null) {
            // if λ¬Έ μ§„μž… μ‹œμ—λ§Œ Singleton ν΄λž˜μŠ€μ— λŒ€ν•œ 동기화 μž‘μ—… μˆ˜ν–‰
            synchronized (Singleton.class) {
                if (singletonObject == null) {
                    singletonObject = new Singleton();
                }
            }
        }

        return singletonObject;
    }
}

 

5. Enum 방식

  • enum νƒ€μž…μœΌλ‘œ 싱글톀을 μ μš©ν•˜λŠ” 방법.
  • 훨씬 κ°„κ²°ν•˜κ²Œ μ‚¬μš© κ°€λŠ₯ν•˜λ©°, Serialize λ˜λŠ” Reflection κ³΅κ²©μ—μ„œλ„ 싱글톀이 κΉ¨μ§€λŠ” 것을 μ™„λ²½νžˆ 막을 수 있음.
  • λ§Œλ“œλ €λŠ” 싱글톀이 enumμ™Έμ˜ 클래슀λ₯Ό 상속해야 ν•œλ‹€λ©΄ 이 방법은 μ‚¬μš©ν•  수 μ—†μŠ΅λ‹ˆλ‹€. (λ‹€λ§Œ, enum Singleton implements ~와 같이 μΈν„°νŽ˜μ΄μŠ€λŠ” κ΅¬ν˜„ν•˜λ„λ‘ μ„ μ–Έν•  μˆ˜λŠ” 있음)
public enum Singleton {
    INSTANCE;
}

 

<참고 자료>

 

[Java] 싱글톀 νŒ¨ν„΄(Singleton Pattern) - κ°œλ… 및 예제

싱글톀 νŒ¨ν„΄(Singleton Pattern) 싱글톀 νŒ¨ν„΄μ€ 객체 지ν–₯ ν”„λ‘œκ·Έλž˜λ°μ—μ„œ νŠΉμ • ν΄λž˜μŠ€κ°€ 단 ν•˜λ‚˜λ§Œμ˜ μΈμŠ€ν„΄μŠ€λ₯Ό μƒμ„±ν•˜μ—¬ μ‚¬μš©ν•˜κΈ° μœ„ν•œ νŒ¨ν„΄μ΄λ‹€. μƒμ„±μžλ₯Ό μ—¬λŸ¬ 번 ν˜ΈμΆœν•˜λ”λΌλ„ μΈμŠ€ν„΄μŠ€κ°€ ν•˜

ittrue.tistory.com

 

λΈ”λ‘œκ·Έμ˜ 정보

Study Repository

rlaehddnd0422

ν™œλ™ν•˜κΈ°