생성자를 private 으로 선언하고, 클래스의 인스턴스를 생성해 리턴해주는 정적 메소드를 만듦
public class Singleton{
private static Singleton uniqueInstance;
private Singleton() {}
//생성자를 private으로 선언해 해당 클래스 내부에서만 인스턴스 생성 가능
public static Singleton getInstance(){
if(uniqueInstance == null){
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
//기타 메소드..
}
//Singleton.getInstance() 이런식으로 사용하면 됨
"게으른 인스턴스 생성(lazy instantiation)"
필요한 상황이 오기 전까지 인스턴스를 생성하지 않고, 요청을 받을 때 생성하는 방법
public class ChocolateBoiler {
private boolean empty;
private boolean boiled;
public ChocolateBoiler() {
empty = true;
boiled = false;
}
public void fill() {
if(isEmpty()){
empty = false;
boiled = false;
// 보일러에 우유/초콜릿을 혼합한 재료를 집어넣음
}
}
public void boil() {
if(!isEmpty() && !isBoiled()){
//재료를 끓임
boiled = true;
}
}
public boolean isEmpty(){
return empty;
}
public boolean isBoiled(){
return boiled;
}
}
public class ChocolateBoiler {
private boolean empty;
private boolean boiled;
private static ChocolateBoiler uniqueInstance;
private ChocolateBoiler() {
empty = true;
boiled = false;
}
public static ChocolateBoiler getInstance(){
if(uniqueInstance == null){
uniqueInstance = new ChocolateBoiler();
}
return uniqueInstance;
}
public void fill() {
if (isEmpty()) {
empty = false;
boiled = false;
// 보일러에 우유/초콜릿을 혼합한 재료를 집어넣음
}
}
public void boil() {
if (!isEmpty() && !isBoiled()) {
//재료를 끓임
boiled = true;
}
}
public boolean isEmpty() {
return empty;
}
public boolean isBoiled() {
return boiled;
}
}
싱글톤 패턴
싱글톤 패턴은 해당 클래스의 인스턴스가 하나만 만들어지고, 어디서든지 그 인스턴스에 접근할 수 있도록 하기 위한 패턴입니다.
1번 스레드 | 2번 스레드 | uniqueInstance 값 |
---|---|---|
public static Single getInstance() { | null | |
public static Single getInstance() { | ||
if ( uniqueInstance == null ) { | ||
if ( uniqueInstance == null ) { | ||
uniqueInstance = new Singleton(); | object 1 | |
return uniqueInstance; | ||
uniqueInstance = new Singleton(); | object 2 | |
return uniqueInstance; |
public static synchronized Singleton getInstance();
-> 속도 문제 발생 / 사실 동기화가 필요한 부분은 인스턴스 변수에 객체를 대입할 때 뿐인데..
private volatile static Singleton uniqueInstance;
//volatile 키워드를 사용하면 멀티스레딩 환경에서 변수의 가시성을 보장해줌
public static Singleton getInstance(){
if(uniqueInstance == null){
synchronized (Singleton.class){
//동기화 블록 내에서도 한 번 더 null 체크
if(uniqueInstance == null)
uniqueInstance = new Singleton();
}
}
return uniqueInstance;
}
맞음. 따라서 클래스 로더를 여러개 사용하면서 싱글턴을 사용한다면 주의필요. (클래스 로더 직접 지정 등)
전역변수는 객체에 대한 정적 레퍼런스로 '게으른 인스턴스 생성'이 불가하고, 처음부터 끝까지 가지고 있어야함
또한 간단한 객체에 대한 전역 레퍼런스를 자꾸 생성하며 네임스페이스를 지저분하게 만드는 경향이 생김
page 221
getInstance() 동기화 : 속도 문제가 발생할 수 있으나 해당 예제에선 신경쓰지 않아도 될 듯
인스턴스 미리 초기화 : 어차피 초콜릿 보일러는 항상 필요하기 때문에 정적 초기화도 괜찮을 듯
DCL 사용 : 특정 JVM 버전에선 작동하지 않기 때문에 x