728x90
반응형

싱글턴 패턴이란?

"클래스 인스턴스를 하나만 만들고, 그 인스턴스로의 전역 접근을 제공한다."

 

말 그대로 하나의 클래스로 하나의 객체만 만들겠다는 이야기다.

 

이해를 돕기위해 코드를 살펴보자. 아래는 고전적인 싱글턴 패턴을 구현한 것이다.

 

public class Singleton {
    private static Singleton uniqueInstance;

    private Singleton(){}

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

    }
}

자 생성자(Singleton)에 주목해보자. 

private으로 선언함으로써 이 클래스 외에서는 접근이 불가능하다. 즉, new Singleton() 으로 객체 생성이 불가능해진다.

 

그래서 getInstance() 메소드를 통해 static 변수 uniqueInstance에 값이 없으면 객체를 생성해주고, 값이 있으면 그 값을 반환하게 끔 해준다. 이러면 단 Singleton 객체는 단 하나만 존재할 수 밖에 없게 되는 것이다.

 

그런데 위 코드는 멀티 스레딩 시에 문제점이 생긴다. if(uniqueInstance == null) 이 부분에서 각각의 스레드가 true 값을 가지기 때문에 두 개의 스레드에서 각각 객체 생성이 일어난다. 즉, 두 번 이상 객체가 생성되어 싱글턴 패턴에 위반하게 된다. 

 

그러면 어떻게 해결할까? 다양한 방법이 있다. 한 번 살펴보자.


프로그램 시작 시, 인스턴스 생성하기

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

    private Singleton(){
    }

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

- 처음부터 Singleton2 인스턴스를 만들어보자. 정적 초기화 부분에서 싱글턴 패턴을 생성하면서 스레드를 사용해도 아무 문제 없이 작동하는 것을 확인할 수 있을 것이다.

 


DCL (Double Checking Locking)

public class Singleton {

    private volatile static Singleton instance = null;
    
    private Singleton() {

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

- 인스턴스가 생성되어 있는지 확인 후, 생성되어 있지 않았을 때만 동기화를 시킴

- volatile

    -> 변수를 CPU cache에 저장하지 않고 메모리에서 읽고 저장한다.

    -> 스레드를 사용할 때 다른 프로세서에 있는 cache에 변수값이 저장되어 서로 다른 값을 사용하는 것을 방지한다.

- synchronized

     -> 여러 스레드에서 사용하려고 할 때 locking 매커니즘을 제공하여 한 번에 한 개 스레드만 사용할 수 있도록 한다.

 

 


inner static class 사용

 

public class Singleton {
    private static class InnerSingleton{
       static final Singleton instance = new Singleton();
    }
    
    private Singleton() {
       System.out.println("Singleton constructor");
    }
    
    public static Singleton getInstance() {
       return InnerSingleton.instance;
    }
    
    public void print() {
       System.out.println("Singleton instance hashCode = " + InnerSingleton.instance.hashCode());
    }
}

- 내부 정적 클래스를 사용하면 JVM에서는 해당 싱글턴 클래스를 메모리에 load할 때, 정적 멤버 변수가 없으므로 싱글턴 인스턴스를 생성하지 않는다.

 


enum

자 이제까지 싱글턴 패턴의 원리를 알아봤다. 근데 사실 enum 키워드로 모든 것이 해결된다.

public enum Singleton3{
    UNIQUE_INSTANCE;
}

... 

728x90
반응형

+ Recent posts