Notice
Recent Posts
Recent Comments
Link
«   2025/05   »
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
Archives
Today
Total
관리 메뉴

JAVA Developer Training

싱글톤 패턴 (Singleton Pattern) 본문

디자인패턴

싱글톤 패턴 (Singleton Pattern)

Romenest 2021. 10. 5. 14:19
싱글톤 패턴
( Singleton Pattern )

 

어플리케이션이 실행될때 최초 1회만 메모리를 할당하고 그 메모리에 인스턴스를 만들어 사용하는 디자인패턴

생성자가 여러번 호출 되더라도 실제로 생성되는 객체는 하나이며 최초 생성 이후 호출된 생성자는 최초 생성된 객체를 반환한다.

  • 주로 공통된 객체를 여러개 생성해서 사용할때 사용된다. 
  • 대표적인 예로 도메인관점으로 인스턴스가 한개만 존재하는것을 보증하고 싶을 경우 사용한다.

 

장점
  • 한번의 객체생성으로 재사용이 가능하기때문에 메모리 낭비를 방지할 수 있다.
  • 또한 한번의 생성으로 *전역성을 띄기에 다른 객체와 공유가 용이하다. 

*공통으로 사용되는 인스턴스 이기에 다른클래스의 인스턴스들이 접근하여 사용할 수 있다.

단, 여러클래스의 인스턴스가 동시에 싱글톤 인스턴스에 접근하게되면 동시성 문제가 발생 할 수 있다.

 

 

단점
  • 싱글톤 인스턴스가 너무많은 일을 하거나 많은 데이터를 공유시킬 경우 클래스의 인스턴스간 결합도가 높아져 개방 폐쇄 원칙( OCP )을 위배하게된다.

즉, *수정,보수가 힘들어지고 테스트하기가 까다로워진다.

*결합도가 높아진 상태에서 수정할 경우 싱글톤 인스턴스를 사용하는 곳에서 사이드 이펙트 발생확률이 생기게된다.

 

  • 멀티쓰레드 환경에서 일어나는 동시성 문제
  • 자식클래스를 만들수 없다는 점과, 내부 상태를 변경하기 어렵다는 점등 여러 문제점들이 있으며 

결과적으로 싱글톤 패턴은 유연성이 떨어지는 패턴이라고 할 수 있다.

 

예제코드

하나의 프린터기를 여러명의 사원이 사용하는경우 

 public class Printer {
    	private static Printer printer = null;
    
    	private Printer(){
        }
    
    	public static Printer getInstance() {
    		if(printer == null) {
    			printer = new Printer();
    		}
    		return printer;
    	}
    
    	public void print(String input) {
    		System.out.println(input);
    	}
    }

싱글톤을 사용한 예제

기본생성자인 Printer를 private로 외부에서 생성할수 없게 만들고 getInstance를 통해 기존 인스턴스가 없다면 printer를 만들고 있다면  만들어진 printer를 return 해줌으로써 하나의 인스턴스만 유지되게 한다.

 

그러나 위에서 말한 싱글톤 패턴의 단점이 이 코드에서도 들어나는데

바로 멀티 쓰레드 환경에서는 안전하지 않다는 점이다

public static Printer getInstance() {
	if(printer == null) {
		printer = new Printer();
	}
	return printer;
}

멀티쓰레드 즉 하나의 프로세스에서 둘이상의 쓰레드가 작업되는 환경에서는 안전하지 않다는점이다

-위 예시에서는 하나의 프린트를 동시에 2명이상이 사용하는경우를 말하겠다.

 

 public class Printer {
    	private static Printer printer = null;
    	private int count = 0;
    
    	private Printer(){}
    
    	public static Printer getInstance() {
    		if(printer == null) {
    			printer = new Printer();
    		}
    		return printer;
    	}
    
    	public void print(String input) {
    		count++;
    		System.out.println(input + "count : "+ count);
    	}
    }

 

여러쓰레드가 공유되는 상황에서는 해당 조건문이 동시에 여러번 돌수있기때문에 인스턴스가 하나가 아니게 될 수 있다는 점이 문제가 된다

동시 접근시 count값이 각각 제멋대로 일 수 가 있다는 점또한 문제가 될 수 있다.

 

 

해결방법

멀티쓰레드 환경에서 싱글톤의 문제를 해결하기 위해서는 아래와 같은 방법이 있다.

  • 정적 변수에 인스턴스를 만들어 즉시 초기화하는 방법

정적 변수는 객체가 생성되기전 클래스가 메모리에 로딩할 떄 만들어져 최초 초기화 한번이 이루어진다.

또한 정적 변수는 프로그램 시작부터 끝까지 없어지지않고 메모리에 있으며 클래스에 생성된 모든 객체에서 참조할 수 있다.

 

 public class Printer {
    	private static Printer printer = new Printer();
    	private static int count = 0;
    
    	private Printer(){}
    
    	public static Printer getInstance() {
            if(printer == null) {
    			printer = new Printer();
    		}
    		return printer;
    	}
    
    	public synchronized static void print(String input) {
    		count++;
    		System.out.println(input + "count : "+ count);
    	}
    }

위 예시에서 count 값은 각기 다르게 접근하기 때문에 쓰레드마다 값이 달라진다. 이를 해결하기 위해서

synchronized 라는 키워드를 통해 여러 쓰레드에서 동시접근하는 것을 막는 방법으로 해결 할 수 있다.

 

 

간략한 정리

싱클톤은 프로그램 전체에서 하나의 인스턴스만을 공통으로 사용한다.

그렇기 때문에 인스턴스를 이용하는 각 객체간의 결합도가 높아지고 변경에 대해 유연하게 대처할 수 없다.

그러나 하나의 인스턴스를 재사용 하기 때문에 메모리 낭비를 최소화 할 수 있다는 장점을 가지고 있다.