본문 바로가기
개발/JAVA

[JAVA] 싱글톤 패턴(Singleton Pattern) : 멀티 스레드 환경에서의 문제점

by zuzuu 2022. 2. 10.
반응형

 

싱글톤 패턴이란?

한마디로 정의하자면 '객체를 단 하나만 생성하도록 하는 디자인 패턴'!

static이기 때문에 고정된 메모리 영억을 얻으며, 모든 클라이언트(클래스)에서 해당 인스턴스를 사용할 수 있어서 공통된 객체를 다수의 클라이언트에서 사용해야하는 상황에서 주로 사용 된다.

 

싱글톤 패턴의 예제를 보면 아래와 같은 형태가 대부분이다.

본인도 싱글톤 클래스를 작성할 때 이렇게 작성하였는데, 이런 경우 멀티스레드 환경에선 두개 이상의 스레드가 getInstance()를 하게 될 경우 두개의 인스턴스가 생성되는 문제가 생길 수 있다. (= 동시성 문제, thread unsafe)

public class Singleton {
    private static Singleton singleton = null;

    private Singleton(){}

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

 

해결 방법

1.  인스턴스를 호출할 때 생성하지 않고, 처음부터 생성하는 방법.

이런 경우 불필요한 경우에도 인스턴스가 생성되므로 리소스가 낭비된다.

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

    private Singleton(){}

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

 

2. Thread safe Lazy initialization 방법 - synchronized

synchronized 키워드를 사용해서 getInstance() 메소드를 동기화 시킴으로써 thread-safe하게 만들 수 있다.

하지만 큰 성능저하가 발생하므로 권장하지 않는 방법이다.

public class Singleton {
    private static Singleton singleton = null;

    private Singleton(){}

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

 Double-checked locking을 통해 성능 저하를 완화시키는 방법도 있다는데 완벽한 방법은 아니라고 한다.  

 

3. Holder initialization 방법 - LazyHolder

가장 많이 사용되고 있는 해결 방법으로 getInstance()메서드에서 LazyHolder.INSTANCE를 호출하는 순간 Class가 로딩되며 초기화가 진행되고, 이 시점에 thread-safe를 보장한다.

public class Singleton {
    private Singleton(){}

    public static Singleton getInstance(){
        return LazyHolder.INSTANCE;
    }
	
	private static class LazyHolder {
 		public static final Singleton INSTANCE = new Singleton();
    }
}

이 방법을 사용하여 멀티 스레드 환경에서의 발생할 수 있는 문제점을 해결하였다.

 

 

참고 : https://jeong-pro.tistory.com/86

728x90
반응형

댓글