[Java] 싱글톤 패턴 구현

ss9909·2022년 9월 5일
0

Java

목록 보기
5/5

싱글톤은 디자인 패턴중 하나다
해당 클래스에 해당하는 객체를 하나만 생성하는 디자인 패턴이다.

1. Eager Initialization

public class SingletonClass() {
    // private static으로 singletonInstance를 생성하였다.
    private static SingletonClass singletonInstance = new SingletonClass();

    // 생성자를 private으로 생성해 다른 클래스에서 호출할 수 없다.
    private SingletonClass(){}

    // getInstance 메서드를 통해 singletoneInstance를 호출
    public getInstance(){
        return singletoneInstance;
    }
}

직관적으로 가장 쉽게 싱글턴 객체를 생성하는 방법이다.

문제점

  • 전혀 생성할 필요가 없는 경우에도 생성하기 때문에 메모리를 낭비하는 결과를 초래할 수 있다.
  • 싱글턴은 만족하였으나, 현재는 문제가 생겼을 때 추적할 수 없다.

우선 문제를 추적할 수 있도록 변경해보자.

2. Static block Initialization

public class SingletonClass() {
    // private static으로 singletonInstance를 생성하였다.
    private static SingletonClass singletonInstance;

    // 생성자를 private으로 생성해 다른 클래스에서 호출할 수 없다.
    private SingletonClass(){}

    // static block 안에 singletonInstacne 가져올 수 있게 변경
    // 예외를 던질 수 있게 변경
    static{ 
        try{
            singletoneInstance = new SingletonClass();
        }catch(exception e){
            throw new RuntimeException("Exception occured in creating singleton instance");
        }
    }
    
    // getInstance() 메소드를 통해 singletonInstance를 호출
    pulbic getInstance() { 
        return singletonInstance;
    }
}

문제점

  • 인스턴스가 사용되지 않을 때도 생성되는 문제가 있다.

문제를 추적할 수 있게 변경했지만
인스턴스를 원하는 시점에 생성할 수 있도록 변경해보자.

3. Lazy initializtion

public class SingletonClass() {
    // static으로 singletonInstance를 선언하였다.
    static SingletonClass singletonInstance;

    // 생성자를 private으로 생성해 다른 클래스에서 호출할 수 없다.
    private SingletonClass(){}

    // getInstance 메서드를 통해 singletonInstance가 가리키는 값이 null인 경우에만 SingletonClass 객체 생성
    public getInstance(){
        if(singletoneInstance == null){
           singletoneInstance = new SingletoneClass();
        }
    return singletoneInstance
    }
}

이 방식으로 구현할 경우 1, 2번에서 안고 있던 메모리 낭비 문제에 대해 해결된다.
방법으로 구현을 해도 괜찮은 경우는 single-thread 환경이 보장된 경우다.

문제점

multi-thread 환경에서 동기화?

만약 인스턴스가 생성되지 않은 시점에서 여러 쓰레드가 동시에 getInstance()를 호출한다면 예상치 못한 결과를 얻을 수 있으며, 단 하나의 인스턴스를 생성한다는 싱글톤 패턴에 위반하는 문제점이 야기될 수 있다.

멀티 스레드 환경에서는 어떻게 싱글턴을 보장할 수 있을까?

4. Thread-safe singleton

해당 메서드가 실행 될 때 synchronized키워드를 통해서 막아버리면 다른 스레드들이 해당 메서드에 접근 할 수 없게 되고 그럼 하나의 인스턴스만을 가질 수 있다.

public class SingletonClass() {
    // static으로 singletonInstance를 선언하였다.
    static SingletonClass singletonInstance;

    // 생성자를 private으로 생성해 다른 클래스에서 호출할 수 없다.
    private SingletonClass(){}

    // getInstance 메서드를 통해 singletonInstance가 가리키는 값이 null인 경우에만 SingletonClass 객체 생성
    // synchronized 키워드를 통해 해당 메서드에 하나의 스레드만이 접근할 수 있다. 
    public synchronized getInstance(){
        if(singletoneInstance == null){
           singletoneInstance = new SingletoneClass();
        }
    return singletoneInstance
    }
}

문제점

  • 멀티스레드 환경에서 싱글턴을 보장하기 위해 너무 많은 희생을 치르고 있다. synchronized 키워드는 자주 호출될 경우 스레드들이 제대로 동작하지 못한다.

getInstance 메서드를 다음과 같이 바꿔서 문제를 해결 한다.

public static Singleton getInstance(){
    if(singletonInstance == null){
        synchronized (SingletonClass.class) {
            if(singletonInstance == null){
                instance = new SingletonClass();
            }
        }
    }
    return instance;
}
profile
이름 짓는 게 어려운 사람

0개의 댓글