Singleton Pattern (디자인 패턴 5장)
싱글턴 패턴 정의
싱글턴 패턴은 해당 클래스의 인스턴스가 하나만 만들어지고, 어디서든지 그 인스턴스에 접근할 수 있도록 하기 위한 패턴입니다.
싱글턴 패턴 사용방법은 크게 3가지로 나뉘어진다.
- getInstance() 메소드에 synchronized 키워드를 사용
- 인스턴스를 필요할 때 생성하지 말고, 처음부터 만듦
- DCL(Double-Checking Locking) 을 써서 getInstance()에서 동기화 되는 부분을 줄임
첫번째 방법부터 보자.
class Singleton {
private static Singleton uniqueInstance;
private Singleton() {//생성자를 외부에서 사용하지 못하도록 private 으로 셋팅
}
public static synchronized Singleton getInstance() {
//synchronized 를 사용해 서로 다른 스레드에서 실행 시 하나의 스레드가 끝난 뒤 다른 스레드가 접근 가능
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
}
위의 방법처럼 메소드를 동기화 하게 되면 속도가 100배 정도 저하된다고 한다. 속도가 크게 중요하지 않은 부분에서 사용하면 괜춘~!
두번째 방법을 보자.
class Singleton {
private static Singleton uniqueInstance = new Singleton();//정적 초기화 부분에서 생성
private Singleton() {
}
public static Singleton getInstance() {
return uniqueInstance;
}
}
위의 방법처럼 사용하면 JVM에서 Singleton 의 유일한 인스턴스를 생성해준다. JVM에서 유일한 인스턴스를 생성하기 전에는 어떤 스레드도 uniqueInstance 에 접근 할 수 없다.
세번째 방법을 보자.
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;
}
}
volatile 키워드를 사용하면 멀티 스레딩을 쓰더라도 uniqueinstance 변수가 Singleton 인스턴스로 초기화 되는 과정이 올바르게 진행되도록 할 수 있다.
하지만 자바5 보다 전에 나온 버전의 JVM 을 사용해야 한다면 DCL을 사용할 수 없다.
일반적인 변수의 값은 CPU cache 를 통해 가져 오는데 volatile 키워드를 사용하면 CPU cache가 아닌 MainMemory 에서 가져온다.
그렇기 떄문에 읽고 쓰는 작업을 할 때 제대로 된 값을 읽고 쓸 수 있다.
하지만 멀티 스레드에서 값을 가져올 때 synchronized 를 사용하지 않고 가져오면 완벽하게 보장 되지 않기 때문에 위의 코드를 보면 volatile uniqueInstance 를 초기화 할때 synchronized 를 사용한 것을 볼 수 있다.
이렇게 사용함으로써 안전하게 초기화 하고 instance를 가져와서 사용할 수 있다.
코틀린에서는 아주 간단하게 싱글턴을 만들어 사용한다.
object Singleton {
}
위의 코드가 끝이다.
해당 코틀린 코드는 자바로 Decompile 했을때 1,2,3 방법 중 어떤 방법으로 만들어 질까 궁금해서 한번 해봤다.
Android Studio 에서 Menu > Tools > Kotlin > Show Kotlin Bytecode > Decompile !!
public final class Singleton {
public static final Singleton INSTANCE;
private Singleton() {
}
static {
Singleton var0 = new Singleton();
INSTANCE = var0;
}
}
두번째 방법으로 만들어지는걸 볼 수 있었다.
이상 싱글턴 패턴에 대해 알아보았다.
참고 URL
http://tutorials.jenkov.com/java-concurrency/volatile.html