[Design Pattern] Singleton 패턴이란
zl존석동
·2021. 12. 31. 21:05
소프트웨어 디자인 패턴 중 하나인 싱글톤 패턴에 대해 공부하자!
Singleton 패턴이란?
Singleton 패턴이란?
인스턴스를 필요할 때마다 계속해서 만들지 않고 메모리 내에 단 한번만 생성한 다음 재사용하기 위한 디자인 패턴이다.
왜 사용할까??
다른 클래스의 인스턴스들에서 사용되고 공유되어야 하는 단 하나의 객체가 필요할 때 사용한다.
한번의 객체 생성으로 같은 것을 재사용 할 수 있기 때문에 메모리 낭비를 방지할 수 있다.
문제점
싱글톤 객체가 너무 많은 데이터를 공유시킬 경우 클래스간 결합도가 높아져 유지보수와 테스트가 어려워질 수 있다.
멀티 스레드 환경에서 동기화 처리를 하지 않으면 하나의 인스턴스가 보장되지 않을 수 있다.
사용법(Java)
기본 방식으로의 구현
public class MySingleton {
private static MySingleton instance;
private MySingleton() {
System.out.println("My Singleton 초기화!!" + (int)(Math.random()*1000));
}
public static MySingleton getInstance() {
if(instance == null) {
instance = new MySingleton();
}
return instance;
}
}
생성자를 private으로 두어 외부에서 초기화 할 수 없게 하면서 static 을 통해 단 한번만 객체가 생성되게끔 한 것이다.
위의 클래스를 어디서 몇번을 호출해도 최초에 초기화 된 객체를 불러와 사용하게 된다.
Thread Safe?
저대로는 100% 보장할 수 없다.
위의 싱글톤 클래스를 아래의 코드처럼 멀티 스레드 환경에서 호출하게 될 경우 단 하나임을 보장해주지 못한다.
public class MultiMain {
public static void main(String[] args) {
// TODO Auto-generated method stub
MultiThread[] mt = new MultiThread[2];
for (int i = 0; i < 2; i++) {
mt[i] = new MultiThread();
mt[i].start();
}
}
}
class MultiThread extends Thread {
MultiThread() {}
public void run() {
try {
MySingleton mySingleton = MySingleton.getInstance();
System.out.println(mySingleton);
/* Source */
} catch (Exception e) {
e.printStackTrace();
}
}
}

두 개의 스레드가 각각 순차적이라는 보장이 없기 때문에
instance == null 조건을 둘 다 만족하게 되어버려 인스턴스가 두 개 생성된다.
Thread Safe!
다중 스레드에서도 단 하나임을 보장해줄 수 있도록 싱글톤 클래스를 구현해보자.
1. Synchronized
Synchronized 키워드를 붙이면 하나의 스레드가 해당 메소드를 호출하여 종료시킬 때 까지
다른 스레드들이 접근할 수 없도록 Lock 을 걸어버린다.
단어 그대로 스레드를 동기화 시켜버리기 때문에 처리 성능 저하가 심하다.
public class MySyncSingleton {
private static MySyncSingleton instance;
private MySyncSingleton() {
System.out.println("My Sync Singleton 초기화!!" + (int)(Math.random()*1000));
}
public static synchronized MySyncSingleton getInstance() {
if (instance == null) {
instance = new MySyncSingleton();
}
return instance;
}
}
2. Static 초기화
Thread-Safe 하지 않은 방법과 유사하지만
필요한 시점에 인스턴스로 생성되는 것이 아니라 미리 생성되는 것이 차이점이다.
미리 생성되기 때문에 Thread-Safe 하고 반드시 사용 될 것으로 예상이 된다면 가장 좋은 방법이지 않을까 생각한다.
public class MyStaticSingleton {
//
private static MyStaticSingleton instance = new MyStaticSingleton();
private MyStaticSingleton() {
System.out.println("My Singleton 초기화!!" + (int) (Math.random() * 1000));
}
public static MyStaticSingleton getInstance() {
return instance;
}
}
3. Lazyholder Singleton
싱글톤 클래스 안에 클래스를 두어 JVM에서 클래스가 단 하나만 로드됨을 이용하는 방법이다.
MyLazyHolderSingleton 싱글톤 클래스가 로드될 때 LazyHolder 클래스는 로드되지 않지만 최초로 getInstance()
메소드가 호출되는 시점에 LazyHolder 클래스가 로드되게 된다.
LazyHolder 클래스 로드 시점에 INSTANCE 가 단 한번만 생성되며 값이 재할당 될 수도 없다.
이 방법으로 다중스레드에도 안전하면서 객체가 필요해지는 시점까지 초기화를 지연시킬 수 있게 된다.
public class MyLazyHolderSingleton {
private MyLazyHolderSingleton() {
System.out.println("My Sync Singleton 초기화!!" + (int) (Math.random() * 1000));
}
public static MyLazyHolderSingleton getInstance() {
return LazyHolder.INSTANCE;
}
private static class LazyHolder {
private static final MyLazyHolderSingleton INSTANCE = new MyLazyHolderSingleton();
}
}
ref
'Design pattern' 카테고리의 다른 글
| [Design Pattern] 설명하기 쉽지 않은 MVC Pattern (0) | 2021.12.23 |
|---|