티스토리 뷰

Design pattern

싱글톤 패턴(Singleton Pattern)

영지는 달리는중 2020. 12. 18. 15:40

디자인 패턴이란?

좋은 코드를 설계하기 위한 일종의 설계 디자인 방법론

오늘 포스팅할 싱글톤 패턴은 GoF 디자인 패턴 중 생성 패턴의 한 종류이다 

 

 

싱글톤(Singlenton)이란?

싱글톤 패턴은 객체의 인스턴스를 하나만 생성하는 방식을 말한다. 

생성자가 여러 차례 호출되더라도 실제로 생성되는 객체는 하나이고 최초 생성 이후에 호출된 생성자는 최초의 생성자가 생성한 객체를 리턴하게 된다. 이렇게 최초에 생성한 하나의 인스턴스를 메모리에 등록하여 여러 스레드가 동시에 해당 인스턴스를 공유하며 사용하게끔 할수 있으므로 요청이 많은 곳에서 사용하면 효율을 높일 수 있다. 

 

싱글톤을 사용하는 이유?

메모리 낭비를 방지할 수 있다. 전역성을 띄는 객체이므로 다른 객체와 공유가 가능하다.

 

멀티 스레드 환경에서 싱글톤 패턴 사용시 주의할 점

- 동시성(Concurrency) 문제 고려해야 한다 (Thread-Safe를 보장해야 한다)

 

자바에서 싱글톤 패턴 사용하기 

 

1. static 키워드 사용

static 키워드의 특징을 이용해서 클래스 로더가 초기화 하는 시점에 정적 바인딩(컴파일 시점)을 통해 해당 인스턴스를 메모리에 등록해서 사용한다.

클래스 로더에 의해 최초로 로딩 될 때 객체가 생성되기 때문에 객체 생성 과정에서 Thread-Safe 하다.

public class Singleton{
//static 키워드를 사용하여 정적 바인딩 실행 
private static Singleton singleton = new Signleton();

//기본 생성자 사용 못하게 막아두기
private Singleton(){}

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

 

2. synchronized 키워드 사용

컴파일 시점이 아닌 인스턴스가 필요한 시점(동적 바인딩)에 요청하여 동적 바인딩을 통해 인스턴스를 생성한다.

Synchronized 선언으로 인하여 하나의 스레드가 해당 메소드를 실행중일 때 다른 스레드가 접근 불가함으로 Thread-Safe가 보장된다.

하짐만 성능이 100배 가량 떨어진다. 

public class Singleton{
private static Singleton singleton;

private Singleton(){}

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

 

3. Double Checking Locking - DCL & volatile 키워드 사용 

위의 동기화 블럭 방식을 개선한 방식이다. 이는 인스턴스가 생성되지 않은 경우에만 동기화 블럭이 실행되게끔 구현한 방식이다.

public class Singleton{
private volatile static Singleton singleton;

private Singleton(){}

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

Volatile 키워드 

멀티 스레드 어플리케이션에서 작업을 수행하는 동안 성능 향상을 위해 Main Memory에서 읽은 변수 값을 CPU Cache에 저장하는데 이때 변수 값 불일치를 해결해주는 역할을 한다.

- 멀티 스레드 환경에서 하나의 스레드가 read and write 하면, 나머지 스레드는 read만 하는 경우 변수 최신 값을 보장

- 멀티 스레드 환경에서 여러개의 스레드가 write 하는 상황이라면 동기화 블럭을 지정해서 원자성을 보장

 

4. Holder 

자바에서 싱글톤 생성에서 사용하는 대표적인 방법이다. 

volatile이나 synchronized 키워드 없이 동시성 문제를 해결하여 Thread-Safe를 보장한다

public class Singleton{
    private Singleton(){}
    
    private static class InnerInstanceClazz(){
        private static final Singleton singleton = new Singleton();
    }
    
    public static Singleton getInstance(){
        return InnerInstanceClazz.instance;
    }
}

 

스프링의 싱글톤 패턴

 

스프링 빈의 기본 Scope는 싱글톤 패턴이고 스프링 환경은 멀티 스레드 환경이다.

 

싱글톤 이외의 Scope 종류들 

- prototype : 컨테이너에 빈을 요청할 때마다 매번 새로운 객체를 만든다.

-request : HTTP 요청 하나당 하나의 객체를 만든다.

 

스프링은 IOC 컨테이너가 모든 빈들을 생명주기를 관리하므로 싱글톤 패턴 역시 IOC 컨테이너가 자동으로 구현하여 관리한다.

좀 더 깊이 들어가보면 IOC 컨테이너에서 빈 관리를 담당하는 BeanFactory의 핵심 구현 클래스는 DefaulttListableBeanFactory이고 이 클래스가 구현하고 있는 인터페이스 중 하나가 SingletonRegistry이다. 

 

스프링은 왜 Bean을 싱글톤으로 생성하나?

스프링에서 하나의 요청(스레드)를 처리하기 위해서는 여러 기능들을 담당하는 객체들이 계층형으로 이루어져 있는데 매 요청마다 객체를 만들어 사용한다면 GC가 있더라도 메모리 부하가 올 수 있다. 

 

싱글톤 Bean을 만들 때 주의사항

- 무상태성(stateless)를 지켜야한다. 즉 상태 정보를 가지는 전역 변수와 같은 것들을 클래스 내부에 가지고 있으면 안된다.  전역변수가 있게되면 여러 스레드가 해당 자원을 공유하게 되므로 Threade-Safe를 보장할 수 없기 때문이다. 

 

궁금했던 점 - Controller 1개가 어떻게 수많은 Request를 처리하는가? 

컨트롤러의 메소드를 각각의 스레드가 공유한다는 것은 동기화와는 전혀 다른 개념이다. lock을 걸고 병목 현상이 일어나고 .. 이런건 생각할 필요가 없다는 말씀! 각 스레드가 무상태성의 메소드를 호출만 하기 때문에 동기화할 필요가 없고 처리 로직만 쓰이기 때문에 요청이 여러개여도 상관이 없다

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/10   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
글 보관함