본문 바로가기

Programming/JAVA

싱글톤(Singleton)을 만들자~~

싱글톤이란 하나의 인스턴스만 생성되는 구조 입니다. 두 가지 방법으로 표현이 가능한데 아래의 예를 참고 바랍니다.

1. public static final 멤버변수만을 이용

        public class SingtonTest {
              public static final SingletonTest instance = new SingletonTest();

              private SingletonTest() {…}
        }

SingletonTest 클래스의 private 생성자는 static 변수인 instance가 초기화 될 때 딱 한번 호출 됩니다. static 변수이므로 실행을 위해 메모리에 로딩될 때 초기화 될 것 입니다.

이러한 경우는 멀티 쓰레드 환경이라도 하나의 유일한 인스턴스를 보장 합니다.


2. public static 메소드를 제공

        public class SingtonTest {
              public static final SingletonTest instance;
               
              private SingletonTest() {…}

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

        Factory 메소드인 getInstance()에서는 하나의 객체에 대한 같은 참조
       를 계속 리턴 하게 되므로 인스턴스의 유일성을 보존 하는 것 입니다.

        이러한 경우는 단일 쓰레드에서는 인스턴스의 유일성을 보장하나
        멀티쓰레드 환경 이라면 하나의 유일한 인스턴스를 보장하지 않습니다.

        즉 멀티쓰레드 환경이라면 다음과 같이 코딩을 해 주어야 합니다.
        (아래에서 getInstance() 메소드 자체를 동기화해도 됨)

        public static SingletonTest getInstance()
        {
          if (instance == null)
          {
               synchronized(SingletonTest.class) {   //-> 다른 쓰레드에 의해 동시에 수행되지 않도록 하기 위해
                     if (instance == null)          instance = new SingletonTest();  
             }
           }
           return instance;
         }


1번의 경우처럼 public static final 멤버변수를 사용하는 경우는 선언 만으로 그 클래스가 싱글톤 이라는 것을 알 수 있고 final 이므로 항상 동일한 객체를 참조 하는 것 입니다.static 메소드를 사용하는 것보다 성능이 약간 낫지만 느끼는 성능차이는 얼마 되지 않을 것 입니다.

2와 같이 static 메소드를 이용하게 되면 기존 클래스의 API는 그대로 유지하면서 싱글톤의 구현을 바꿀 수가 있습니다. 예를 들면 위의 getInstance() 메소드는 Thread 하나당 유일한 인스턴스를 리턴 하도록 변경이 가능 하다는 이야기 입니다.

결론적으로 영원히 싱글톤으로 사용 될 클래스라면 static 멤버변수를 이용하고, 그렇지 않은 경우엔 static 메소드를 이용하는 것dl 좋을 것입니다.

특히 싱글톤 클래스가 직렬화를 제공한다고 할 때 선언부에 implements Serializable 이라고 선언한다고 싱글톤을 보장 받지는 않습니다. 싱글톤임을 확실히 보장 받을려면 readResolve()라는 메소드를 제공해야 하는데 만약 이렇게 하지  않으면 인스턴스를 역직렬화 할 때마다 새로운 인스턴스가 생겨나 가까 SingletonTest 인스턴스가 생겨나게 되는 것입니다.

private Object readResolve() throws ObjectStreamException {
        return instance;
}