객체를 하나만 생성하도록 하며, 생성된 객체를 어디서든지 참조할 수 있도록 하는 패턴
생성 패턴 중 하나
static 블럭 사용시 클래스가 로딩될 때 한번만 실행
인스턴스가 사용되는 시점이 아닌 로딩 시점에 실행된다.
public class Singleton {
private static Singleton singleton;
private Singleton() {
}
static {
try {
singleton = new Singleton();
} catch(Exception e){
...
}
}
public static Singleton getInstance() {
return singleton;
}
}
static 방법을 개선하여 클래스 로딩 시점이 아닌 인스턴스가 필요하여 요청시 생성
→ 특정 쓰레가 동시에 getInstance 호출시 인스턴스가 두번 생성되는 문제 발생
public class Singleton {
private static Singleton singleton;
private Singleton() {
}
public static Singleton getInstance() {
if(instance == null) {
singleton = new Singleton();
}
return singleton;
}
}
synchronized 키워드를 붙임으로서 쓰레드 동시 접근 문제 해결 → synchronized는 성능 저하 발생시킴
public class Singleton {
private static Singleton singleton;
private Singleton() {
}
public static synchronized Singleton getInstance() {
if(instance == null) {
singleton = new Singleton();
}
return singleton;
}
}
java에서 signleton 생성에 사용하는 대표적인 방법
JVM의 클래스 로더 메커니즘과 클래스의 로드 시점을 이용하여 내부 클래스를 통해 생성 시킴으로써 쓰레드 간의 동기화 문제를 해결
public class Singleton {
private Singleton() {
}
private static class InnerInstanceClass(){
private static final Singleton singleton = new Singleton();
}
public static Singleton getInstance() {
return instance;
}
}
메모리 낭비 방지
최초 한번의 new 연산자를 통해 고정된 메모리 영역을 사용
→ 추후 해당 객체에 접근할때 메모리 낭비 방지 가능
이미 생성된 인스턴스를 사용하므로 속도 측면에서도 좋음
쉬운 데이터 공유
전역으로 사용되는 인스턴스 이기때문에 다른 클래스에서 접근하여 사용 가능
단, 여러 클래스에서 동시 접근시 동시성 문제 발생 가능
많은 코드양
싱글톤 패턴 적용을 위해 구현하는 코드 양이 많다.
정적 팩토리 메서드에서 객체 생성 확인 후 생성자를 호출하는 경우 멀티스레딩-동시성 문제 해결을 위해 syncronized 사용
어려운 테스트
자원을 공유하고 있기때문에 테스트가 격리된 환경에서 수행되려면 매번 인스턴스 상태를 초기화 시켜줘야함
클라이언트가 구체 클래스에 의존
new 키워드를 직접 사용하여 클래스안에서 객체를 생성하므로 객체 지향 설계 원칙인 OPC(개방 폐쇄 원칙), DIP(의존 역전 원칙) 위반할 가능성이 있다.
이 외에도 자식 클래스 생성 불가능, 내부 상태 변경 어려움 등 문제 존재
유연성이 많이 떨어지는 패턴