[생성패턴] 1. 싱글톤 패턴

Carrot.___.·2023년 11월 15일

디자인패턴

목록 보기
1/6

싱글톤 패턴이란?

객체의 인스터스를 한개만 생성되게 하는 패턴을 말합니다.

장점

  • 인스턴스가 한개만 존재하게 하고, 해당 객체에 접근할 때 해당 인스턴스를 반환함으로써 메모리 효율성을 가질 수 있습니다.
  • 미리 생성된 인스턴스를 활용하여 속도 측면에서 이점을 가져 올 수도 있다.

단점

  • 자원을 공유하고 있기 때문에, 내부 값 변경의 추적이 어렵다.
  • 따라서, 테스트 환경에서 격리된 환경에서 수행하기 어렵다.

싱글톤 예제 코드 (3가지)

1️⃣ 첫번째 방법

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

우선, 기본적으로 싱글톤 패턴은 private 생성자로 외부에서 객체 인스턴스를 생성하는 것을 막습니다.
그리고, 위에서 static 블록을 보면, 클래스가 처음으로 로드되거나 사용되기 전에 실행되며, 정적 멤버의 초기화를 담당합니다.

위 코드는 문제가 없어보이지만, 멀티 스레드 환경에서 getInstance()를 동시에 호출하면, instance 변수에 동시에 인스턴스가 할당되어 덮어씌워질 수 있고, 이는 싱글톤의 법칙에 어긋남과 서로 다른 스레드에서 동시에 하나의 인스턴스를 바라보지 못합니다.

그렇다면, getInstance() 함수에 synchronized 키워드를 활용하여, 스레드의 동기화를 유지하는 것은 어떨까요?
synchronized 키워드를 사용하면 다음과 같은 효과를 얻을 수 있습니다.
스레드의 동기화 유지해 하나의 인스턴스만 존재하게 할 수 있지만, synchronized로 인한 성능 저하를 일으킬 수 있습니다.

2️⃣ 두번째 방법

public class Singleton {

    private static Singleton instance = new Singleton();
    
    private Singleton() {

    }

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

위 코드는 내부의 static instance 변수는 클래스가 JVM에 로드될 때, 메모리가 할당됩니다.
따라서, 멀티 스레드에서 getInstance()를 호출하면, 인스턴스를 그대로 돌려주면 되기 때문에, 싱글톤을 지킬 수 있습니다.

하지만, 위 코드에도 단점은 있습니다.
바로, getInstance()를 호출하지 않아도 메모리에 할당되기 때문에, 사용하지 않아도 메모리에 할당된다는 문제점이 있습니다.

3️⃣ 세번째 방법

public class Singleton {
    private static class SingleInstanceHolder {
        private static final Singleton INSTANCE = new Singleton();
    }
    
    private Singleton() {

    }

    public static Singleton getInstance() {
        return SingleInstanceHolder.INSTANCE;
    }
}

위 코드는 내부 정적 클래스로 싱글톤 인스턴스를 갖기 때문에, 클래스 로딩 시에 한 번만 실행되고, 이로써 스레드 안전성을 보장합니다. 정적 내부 클래스는 클래스 로딩 시에 초기화되며, 이때 생성된 인스턴스는 싱글톤으로 사용됩니다.

결론

첫번째 방법은 멀티스레드 환경에서 매우 위험하니 당연히 피해야합니다.
하지만, 두번째와 세번째 방법은 메모리 측면을 제외하면, 동작상의 기능은 같습니다.
둘 중 어떤 것을 사용해도 상관없으나, 메모리의 효율성을 생각하면 세번째 방법을 사용하는 것이 좋습니다.

0개의 댓글