싱글톤 패턴

임종혁·2024년 2월 5일

하나뿐인 특별한 객체 만들기

고전적인 싱글턴 패턴 구현법


public class Singleton {

    private  static Singleton uniqueInstance;

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


}

싱글톤 패턴의 정의
싱글턴 패턴은 클래스 인스턴스를 하나만 만들고, 그 인스턴스로의 전역 접근을 제공

  • 싱글턴 패턴을 실제로 적용할 때는 클래스에서 하나뿐인 인스턴스를 관리하도록 만들기
    그리고 다른 어떤 클래스에서도 자신의 인스턴스를 추가로 만들지 못하게 하기

  • 어디서든 그 인스턴스에 접근할 수 있도록 전역 접근 지점 제공
    언제든 이 인스턴스가 필요하면 클래스에 요청할 수 있게 만들어 놓고 요청이 들어오면 하나뿐인 인스턴스 건네주도록 만들기

싱글톤 게으른 방식

private  static Singleton uniqueInstance;

    private Singleton(){}
    public static Singleton getInstance(){
        if(uniqueInstance == null){
            uniqueInstance = new Singleton();
        }
        return uniqueInstance;
    } // 게으른 방식으로 생성 요청이 들어오면 하나뿐인 인스턴스를 건네주도록 만들기 

멀티스레드 싱글톤 문제


다음과 같이 멀티스레드 환경시 인스턴스가 여러개 생기는 문제가 발생

해결방법

1. getInsance()

public class Singleton{
	private static Singleton uniqueInsance;
    
    private Singleton(){}
    
    public static synchronized Singleton getInstance(){
    	if(uniqueInstance == null){
        	uniqueInstance = new Singleton();
        }
        
        return uniqueInstance;
    }
}

getInstance()에 synchronized 키워드만 추가하면 한 스레드가 메소드 사용을 끝내기 전까지 다른 스레드는 기다려야한다.

허나 동기화 할때 속도 문제 발생
동기화가 필요한 시점은 이 메소드가 시작되는 때뿐 uniqueInstance 변수에 Singleton 인스턴스를 대입하면 굳이 이 메소드를 동기화된 상태로 유지할 필요가 없음
처음을 제외하면 동기화는 불필요한 오버헤드만 증가

허나 getInstance() 의 속도가 그리 중요하지 않다면 그냥 냅두기

방법 2. 인스턴스가 필요할때는 생성하지 말고 처음부터 만들기

public class Singleton{
	private static Singleton uniqueInstance = new Singleton();
    
    private Singleton(){}
    
    public static Singleton getInstance(){
    	return uniqueInstance;
    }
}

다음과 같은 방식은 JVM 에서 Singleton 의 하나뿐인 인스턴스를 생성
JVM에서 하나뿐인 인스턴스를 생성하기 전까지 그 어떤 스레드도 uniqueInstance 정적 변수에 접근 할 수 없다

방법 3 DCL 을 써 getInstance() 에서 동기화 되는 부분 줄이기

DCL(Double-Checked Locking) 을 사용하면 인스턴스가 생성되어 있는지 확인한 다음 생성되지 않았을때만 동기화 가능

public class Singleton{

	private volatile static Singleton uniqueInstance;
    
    private Singleton(){}
    
    public static Singleton getInstance(){
    	if(uniqueInstance == null){
        	synchronized(Singleton.class){
            	if(uniqueInstance == null){
                	uniqueInstance = nuew Singleton();
                }
            }
        }
        return uniqueInstance;
    }
}

인스턴스가 있는지 확인하고 없으면 동기화된 블록으로 들어가기
처음에만 동기화후
블록에서 다시 한번 변수가 null 인지 확인한 다음 인스턴스 생성

volatile 키워드를 사용하면 멀티스레딩을 쓰더라도 uniqueInstance 변수가 Singleton 인스턴스로 초기화되는 과정이 올바르게 진행

enum 클래스로 싱글턴 해결

enum 으로 싱글톤 생성해서 해결시 동기화 문제 클래스 로딩 문제 , 리플렉션, 직렬화 , 역직렬화 문제등 해결 가능

public enum Singleton{
	UNIQUE_INSTNACE;
}

public class SingletonClient{
	public static void main(String[] args){
    	Singleton singleton = Singleton.UNIQUE_INSTANCE;
    }
}

다시한번
싱글톤패턴은 클래스 인스턴스를 하나만 만들고 그 인스턴스로 전역 접근 제공하기


정리

  • 어떤 클래스에 싱글턴 패턴을 적용하면 그 클래스의 인스턴스가 1개만 있도록 할 수 있다.
  • 싱글톤 패턴을 사용하면 하나뿐인 인스턴스를 어디서든지 접근할 수 있도록 할 수 잇다.
  • 자바에서 싱글턴 패턴을 구현할 때는 PRIVATE 생성자와 정적 메소드, 정적 변수를 사용한다.
  • 멀티 스레드를 사용하는 애플리케이션에서는 속도와 자원 문제를 파악해보고 적절한 구현법을 사용한다
  • DCL 써서 구현하면 자바 5 이전에 나온 버전에는 스레드 관련 문제가 생길수 있다.
  • 클래스 로더가 여러개 있다면 싱글턴이 제대로 작동하지 않고 여러 인스턴스가 생길수 있다.
  • 자바의 enum을 쓰면 간단하게 싱글톤을 구현 가능하다

0개의 댓글