한 개의 클래스에 오직 한 개의 인스턴스만 존재하도록 하고, 해당 클래스의 인스턴스 접근 시 항상 동일한 인스턴스를 반환하도록 하는 생성 패턴이다.
- Singleton : 하나의 인스턴스만을 생성하고, 항상 동일한 인스턴스 반환
객체를 생성해주는 필드를 static final로 선언 후 객체를 생성하여 필드에 넣어놓고, 외부에서 해당 객체 생성시 기존에 생성한 객체를 반환해준다. 새로 생성하지 못하고 기존의 객체를 반환해 줄 수 있도록 생성자는 private으로 만들어야 한다.
[UserService.java]
public class UserService {
private static final UserService instance = new UserService();
private UserService() {
}
public static UserService getInstance() {
return instance;
}
}
[Client.java]
public class Client {
public static void main(String[] args) {
UserService user1 = UserService.getInstance();
UserService user2 = UserService.getInstance();
System.out.println(user1.equals(user2));
}
}
- 원자성이 결어되어 있음
- 멀티 스레드 환경에서 인스턴스를 2개 이상 만들 수 있음.
public class Singleton {
private static Singleton instance;
private Singleton() {
}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
- 인스턴스 반환하기 전까지 잠금할 수 있음
- getInstance() 메서드 호출할 때마다 잠글이 걸려 성능저하란 단점
public class Singleton {
private static Singleton instance;
private Singleton() {
}
public synchronized static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
- 클래스 로딩 때 인스턴스 생성
- 불필요한 자원낭비
- 인스턴스가 필요없는 경우에도 인스턴스 생성하기 때문
public class Singleton {
private static Singleton instance = new Singleton(); // 정적 멤버
private Singleton() {
}
public static Singleton getInstance() {
return instance;
}
}
public class Singleton {
private static Singleton instance = null;
static { // 정적 블럭
instance = new Singleton();
}
private Singleton() {
}
public static Singleton getInstance() {
return instance;
}
}
- 불필요한 자원낭비 없이 getInstance()가 호출될 때 Holder 클래스가 로딩되어 인스턴스를 생성한다.
public class Singleton {
private static class SingletonInstanceHolder{
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonInstanceHolder.INSTANCE;
}
}
- Double Checked Locking, 잠금 전에 한번, 객체 생성 전에 한번 인스턴스 생성 여부를 체크하면 인스턴스가 존재할 때만 잠금을 걸 수 있기 때문에 앞서 생겼던 문제점을 해결할 수 있다.
public class Singleton {
private volatile Singleton instance;
private Singleton() {
}
public Singleton getInstance() {
if (instance == null) { // 잠금 전에 한번
synchronized (Singleton.class) {
if (instance == null) { // 생성 전에 한번
instance = new Singleton();
}
}
}
return instance;
}
}
- 기본적으로 스레드 세이프 보장
- 멤버 변수화 메서드도 정의 가능
public enum Singleton {
INSTANCE;
private int value = 3;
public int getValue() {
return value;
}
}
주로 4번과 6번이 사용된다.