특정 클래스에 객체 인스턴스가 단 하나만 만들어지도록 해주는 패턴
전역 변수에 객체를 대입하면 애플리케이션이 시작될 때 객체가 생성된다.
그런데 해당 객체가 자원을 많이 잡아먹는다고 가정을 해보자
만약 애플리케이션이 끝날 때까지 그 객체를 한번도 쓰지 않는다면 괜히 자원만 잡아먹는 쓸데없는 객체인 것이다.
만약, 싱글턴 패턴을 사용한다면 필요할 때만 객체를 생성할 수 있다.
어떤 문제점이 있을까?
private static Singleton uniqueInstance;
private Singleton() {}
public static Singleton getInstance() {
//아직 인스턴스가 생성되지 않았다면
if (uniqueInstance == null) {
//인스턴스를 생성하고 정적 변수에 저장한다.
//즉, 인스턴스를 필요로 하는 시점에 인스턴스를 생성한다 -> 게으른 인스턴스 생성
uniqueInstance = new Singleton();
}
//인스턴스가 이미 생성되어 있는 경우는 정적 변수에 저장된 인스턴스를 반환한다.
return uniqueInstance;
}
//기타 메서드
즉 인스턴스가 필요로 한 시점에 정적 메서드로 인스턴스를 달라고 요청하면
1. 인스턴스가 있는 경우 : 정적 변수에 저장된 인스턴스를 리턴
2. 인스턴스가 없는 경우 : 그제서야 인스턴스를 생성하고 정적 변수에 저장
처음부터 정적 변수에 인스턴스를 저장하면 사용하지 않더라도 인스턴스를 생성하여 자원을 잡아먹을 수도 있는데
싱글턴을 사용하면 인스턴스가 필요로 하는 시점에 인스턴스를 생성하기에 자원 낭비가 없다는 장점이 있다.
synchronized 키워드를 이용하면 한 스레드가 메서드 사용을 끝내기 전까지 다른 스레드는 기다려야 한다.
즉, 2개의 스레드가 해당 정적 메서드를 동시에 실행할 수가 없다.
동기화가 필요한 시점은 인스턴스를 생성하는 것 뿐이다.
이후, 생성된 인스턴스를 사용하는 시점은 동기화된 상태가 필요하지 않다.
즉 처음을 제외하면 동기화는 불필요한 오버헤드만 증가시킬 뿐이다.
public class Singleton{
private static Singleton uniqueInstance;
private Singleton() {}
public static synchronized Singleton getInstance() {
//아직 인스턴스가 생성되지 않았다면
if (uniqueInstance == null) {
//인스턴스를 생성하고 정적 변수에 저장한다.
//즉, 인스턴스를 필요로 하는 시점에 인스턴스를 생성한다 -> 게으른 인스턴스 생성
uniqueInstance = new Singleton();
}
//인스턴스가 이미 생성되어 있는 경우는 정적 변수에 저장된 인스턴스를 반환한다.
return uniqueInstance;
}
//기타 메서드
}
성능 문제가 발생한다.
성능이 약 100배 정도 저하된다고 한다.
따라서 getInstance()가 애플리케이션에서 병목으로 작용한다면 다른 방법을 생각해봐야 한다.
애플리케이션에서 반드시 Singleton 인스턴스를 생성하고, 그 인스턴스를 항상 사용한다면 처음부터 Singleton 인스턴스를 만드는 것도 좋다.
클래스가 로딩될 때 JVM에서 Singleton 클래스의 유일한 인스턴스를 생성해준다.
public class Singleton {
private static Singleton uniqueInstance = new Singleton();
private Singleton() {}
public static synchronized Singleton getInstance() {
return uniqueInstance;
}
}
public class Singleton {
private volatile static Singleton uniqueInstance;
private Singleton() {}
public static Singleton getInstance() {
if (uniqueInstance == null) {
synchronized (Singleton.class) {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
}
}
return uniqueInstance;
}
}