Singleton Pattern (싱글턴 패턴)

Singleton Pattern


정의


1.    Singleton Pattern은 해당 Classinstance가 하나만 만들어진다.


2.    어디서든 그 instance에 접근할 수 있게 한다.


3.    class에서 하나뿐인 instance를 관리하게 한다.


4.    Instance가 사용될 때 똑 같은 instance를 만드는 것이 아닌, 동일 instance를 사용하게끔 하는 것이다.

 

고전적인 Singleton Pattern

public class Singleton {
    private static Singleton uniqueInstance;
 
    private Singleton(){}
 
    public static Singleton getInstance() {
        if(uniqueInstance == null){
            uniqueInstance = new Singleton();
        }
        return uniqueInstance;
    }
}

전역변수로 instance를 생성하는데 private static 키워드를 사용한다.


Static이 붙은 class 변수는, 인스턴스화에 상관없이 사용할 수 있다.


하지만, private 접근 제어자로 인해

Singleton.uniqueInstance

와 같은 방법으로 접근할 수 없다


이 상태에서 private 키워드를 붙이는데 그러면 new 키워드를 사용할 수 없게 된다.


그 결과 외부 class가 위 classinstance를 가질 수 있는 방법은, getinstance() method를 사용하는 방법밖에 없다.


 하지만 위의 방법은 Multi-threading과 관련해서 문제가 생긴다


       그 이유는 thread getinstance() method를 호출하면 instance가 두 번 생길 수 있기 때문이다.


       이러한  문제를 방지하기 위해, getinstance() method를 동기화 시킨다.

public class Singleton {
    private static Singleton uniqueInstance;
    // 기타 인스턴스 변수
    private Singleton() {}
    //synchronized 키워드만 추가하면 
    // 두 스레드가 이 메소드를 동시에 실행시키는 일은 일어나지 않게 된다.
    public static synchronized Singleton getInstance() {
        if (uniqueInstance == null) {
            uniqueInstance = new Singleton();
        }
        return uniqueInstance;
    }
}


위와 같이 할 수 있는데 이 방법도 문제가 있다. 수 많은 thread들이 getinstance()

method를 호출하기 위해 동기화 하면 성능이 떨어진다.

이러한 문제를 방지하기 위해서 instance를 필요할 때 생성하는 것이 아니라, 처음부터 생성하는 방법이 있다.

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

위와 같이 하는 방법 외에도 DCL(Double-Checking Locking)을 사용하여 getinstance()에서 동기화되는 부분을 줄이는 방법이 있다.


DCL을 사용하면 instance가 생성되어 있는지 확인한 후, 생성이 되어있지 않을 때만 동기화를 할 수 있다


Volatile 키워드를 사용해서 multi-threading을 사용하더라도변수가 Singleton instance로 초기화 되는 과정이 올바르게 할 수 있다.

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;
    }
}