본문 바로가기
FullStack/21. Java

[Java] 다양한 싱글톤 생성 방법

by nakanara 2021. 5. 10.
반응형

디자인 패턴 중 자주 사용하는 싱글톤에 대해서, 해당 생성 방식에 따른 차이점을 정리하였다.

1. 빠른 생성

디자인 패턴 책에서 많이 사용되고 있는 예제이며,
클래스가 로딩되는 시점에서 싱글톤 클래스를 생성하여 사용되는 간단하면서 명확한 예제

단점

  • 프로그램에서 해당 클래스를 사용하지 않아도 싱글톤을 객체가 생성
  • 객체 생성 시점에서 발생하는 예외에 대한 처리 불가
public class EagerSingleton {

    private static final EagerSingleton instance = new EagerSingleton();

    private EagerSingleton(){
        // todo exception~
    }

    public static EagerSingleton getInstance() {
        return instance;
    }
}

2. 정적 블록을 이용한 초기화

정적 블록을 이용하여 초기화하는 방법으로
객체를 빠르게 생성하는 것은 동일하며, 예외처리 또한 가능

단점

  • 프로그램에서 해당 클래스를 사용하지 않아도 싱글톤을 객체가 생성
public class StaticBlockSingleton {

    //private static final StaticBlockSingleton instance = new StaticBlockSingleton();
    private static StaticBlockSingleton instance;

    static {
        try {
            instance = new StaticBlockSingleton();
        }catch(Exception e) {
            // todo
        }
    }

    private StaticBlockSingleton(){}

    public static StaticBlockSingleton getInstance() {
        return instance;
    }

}

3. 지연 초기화

사용하는 시점에서 인스턴스 생성

단점

  • 멀티 스레드 환경의 경우 동시에 getInstance를 호출할 경우 서로 다른 싱글 톤 객체를 생성할 가능성 존재
public class LazySingleton {

    private static LazySingleton instance;

    private LazySingleton(){}

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

4. 스레드에 안전한 싱글톤

싱글톤을 생성하는 getInstance함수를 동기화(synchronized)로 지정하여, 한 번에 하나의 스레드만 사용할 수 있도록 설정

단점:

  • 함수 동기화(synchronized)로 인한 성능 저하 예상
public class ThreadSafeSingleton {

    private static ThreadSafeSingleton instance;

    private ThreadSafeSingleton(){}

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

}

getInstance함수 자체에 동기화가 설정되어 있어,
객체 생성 여부까지 판단하여 진행하는 경우 많은 비용으로 인한 성능 저하가 발생할 가능성이 있으므로, 이를 수정하여 객체가 없는 경우 생성하는 부분에서만 동기화하여 생성하는 방식으로 변경

public class ThreadSafeDoubleLockingSingleton {

    private static ThreadSafeDoubleLockingSingleton instance;

    private ThreadSafeDoubleLockingSingleton(){}

    public static ThreadSafeDoubleLockingSingleton getInstance() {
        // 생성되지 않은 경우 동기화(synchronized) 선언
        if(instance == null) {
            synchronized (ThreadSafeDoubleLockingSingleton.class) {
                if(instance == null) {
                    instance = new ThreadSafeDoubleLockingSingleton();
                }
            }
        }
        return instance;
    }
}

5. 내부 정적 도우미 클래스를 이용한 싱글 톤

Bill Pugh는 내부 정적 도우미 클래스를 사용하여 싱글 톤 클래스를 만드는 방법을 제시

JLS(Java Language Specification)에 정의된 대로 JVM 내의 실행 초기화 단계에 의존
LazyHolderSingleton 클래스에는 초기화할 정적 변수가 없기 때문에 간단하게 초기화가 되며, LazyHolder 안의 INSTANCE는 외부 클래스의 getInstance가 호출되는 시점에 초기화가 시작

또한, 클래스 초기화 단계는 JLS에 의해 순차적(비 동시적)을 보장하므로 getInstance에 동기화(synchronized) 기능이 명시적으로 필요하지 않음

만약 LazyHolderSingleton 생성에 오류가 발생한다면 NoClassDefFoundError이 발생할 수 있음

public class LazyHolderSingleton {


    private LazyHolderSingleton(){}

    // 내부 정적 도우미 클래스
    private static class LazyHolder{
        private static final LazyHolderSingleton INSTANCE = new LazyHolderSingleton();
    }


    public static LazyHolderSingleton getInstance() {
        return LazyHolder.INSTANCE;
    }

}

참조

#singletone #싱글톤 #bullpugh

반응형