Singleton Design Pattern - DanielWorld/SoftwareTech GitHub Wiki
Singleton Design Pattern μ΄λ?
νλμ ν΄λμ€μ νλμ κ°μ²΄λ§ μμ± νλλ‘ νλ©°, μμ±λ κ°μ²΄λ₯Ό μ΄λμμλ μ§ μ°Έμ‘°ν μ μλλ‘ νλ ν¨ν΄ νλμ μΈμ€ν΄μ€λ§μ μμ±νλ μ± μμ΄ μμΌλ©° getInstance μ μ λ©μλλ₯Ό ν΅ν΄ λͺ¨λ ν΄λΌμ΄μΈνΈμκ² λμΌν μΈμ€ν΄μ€λ₯Ό λ°ννλ μμ μ μννλ€.
Singleton Pros and Cons
- μ₯μ :
- κ³ μ λ λ©λͺ¨λ¦¬ μμμ μ»μΌλ©΄μ νλ²μ newλ‘ μΈμ€ν΄μ€λ₯Ό μ¬μ©νκΈ° λλ¬Έμ λ©λͺ¨λ¦¬ λλΉλ₯Ό λ°©μ§ν μ μμ
- κ°μ²΄μ μμ±κ³Ό μ‘°ν©μ μΊ‘μνν΄ νΉμ κ°μ²΄κ° μμ±λκ±°λ λ³κ²½λμ΄λ νλ‘κ·Έλ¨ κ΅¬μ‘°μ μν₯μ ν¬κ² λ°μ§ μλλ‘ μ μ°μ±μ μ 곡νλ€.
- λ§€λ² νΉμ κ°μ²΄λ₯Ό μμ±ν νμ μμ΄ νλλ§ μμ±λ κ°μ²΄λ₯Ό μ΄λμμλ μ§ μ°Έμ‘°ν μ μλ€. μ€μνμ μ μ©νμλ©΄ νλ¦°ν° νλλ₯Ό μ¬λ¬λͺ μ΄μ μ¬μ©ν κ²½μ°λ₯Ό μλ‘ λ€ μ μλ€. μλλ‘μ΄λ μ± κ°μ κ²½μ° κ° μ‘ν°λΉν°λ ν΄λμ€λ³λ‘ μ£Όμ ν΄λμ€λ€μ μΌμΌμ΄ μ λ¬νκΈ°κ° λ²κ±°λ‘κΈ° λλ¬Έμ μ±κΈν€ ν΄λμ€λ₯Ό λ§λ€μ΄ μ΄λμλ μ κ·Όνλλ‘ μ€κ³νλ κ²μ΄ νΈν¨
- λ¨μ :
-
μ±κΈν€ μΈμ€ν΄μ€κ° λ무 λ§μ μΌμ νκ±°λ λ§μ λ°μ΄ν°λ₯Ό 곡μ μν¬ κ²½μ° λ€λ₯Έ ν΄λμ€μ μΈμ€ν΄μ€λ€ κ°μ κ²°ν©λκ° λμμ Έ κ°λ°©-νμ μμΉ μ μλ°°νκ² λλ€. (κ°μ²΄ μ§ν₯ μ€κ³ μμΉμ μ΄κΈλ¨) λ°λΌμ μμ μ΄ μ΄λ €μμ§κ³ ν μ€νΈνκΈ° μ΄λ €μμ§λ€.
-
multithreading νκ²½μμ Singleton ν¨ν΄μ μ¬μ©ν ν΄λμ€μ μ κ·Όν λ, instance κ° 1κ° μ΄μ μμ±λλ κ²½μ°κ° λ°μ (κ²½ν© μ‘°κ±΄) -> Lazy initialization (λ¦μ μ΄κΈ°ν λ°©μ)μ μ¬μ©ν κ²½μ° λ¬Έμ κ° λ°μ
κ²°λ‘ : κΌ νμν κ²½μ°μλλ©΄ μ§μν΄μΌν¨. (μ μ ν μ μ°λ©΄ μμ£Ό μ’μ)
How to avoid race condition of Singleton in Multithreading
- μ μ λ³μμ μΈμ€ν΄μ€λ₯Ό λ§λ€μ΄ λ°λ‘ μ΄κΈ°ννλ λ°©λ² (Eager Initialization)
public class Printer {
// static λ³μμ μΈλΆμ μ 곡ν μκΈ° μμ μ μΈμ€ν΄μ€λ₯Ό λ§λ€μ΄ μ΄κΈ°ν
private static Printer printer = new Printer();
private Printer() { }
// μκΈ° μμ μ μΈμ€ν΄μ€λ₯Ό μΈλΆμ μ 곡
public static Printer getPrinter(){
return printer;
}
public void print(String str) {
System.out.println(str);
}
}
static λ³μ : κ°μ²΄κ° μμ±λκΈ° μ ν΄λμ€κ° λ©λͺ¨λ¦¬μ λ‘λ©λ λ λ§λ€μ΄μ Έ μ΄κΈ°νκ° ν λ²λ§ μ€νλλ€. : νλ‘κ·Έλ¨ μμ~μ’ λ£κΉμ§ μμ΄μ§μ§ μκ³ λ©λͺ¨λ¦¬μ κ³μ μμ£Όνλ©° ν΄λμ€μμ μμ±λ λͺ¨λ κ°μ²΄μμ μ°Έμ‘°ν μ μλ€.
μ₯μ : staticμΌλ‘ μμ±λ λ³μμ μ±κΈν€ κ°μ²΄λ₯Ό μ μΈνκΈ° λλ¬Έμ ν΄λμ€ λ‘λμ μν΄ ν΄λμ€κ° λ‘λ© λ λ μ±κΈν€ κ°μ²΄κ° μμ±λ©λλ€. λ ν΄λμ€ λ‘λμ μν΄ ν΄λμ€κ° μ΅μ΄ λ‘λ© λ λ κ°μ²΄κ° μμ±λ¨μΌλ‘ Thread-safeν©λλ€.
λ¨μ : μ±κΈν€κ°μ²΄ μ¬μ©μ 무μ κ΄κ³μμ΄ ν΄λμ€κ° λ‘λ©λλ μμ μ νμ μ±κΈν€ κ°μ²΄κ° μμ±λκ³ , λ©λͺ¨λ¦¬λ₯Ό μ‘κ³ μκΈ° λλ¬Έμ λΉν¨μ¨μ μΌ μ μλ€.
- μΈμ€ν΄μ€λ₯Ό λ§λλ λ©μλμ λκΈ°ννλ λ°©λ² (Thread-Safe Initialization)
public class Printer {
// μΈλΆμ μ 곡ν μκΈ° μμ μ μΈμ€ν΄μ€
private static Printer printer = null;
private int counter = 0;
private Printer() { }
// μΈμ€ν΄μ€λ₯Ό λ§λλ λ©μλ λκΈ°ν (μκ³ κ΅¬μ)
public synchronized static Printer getPrinter(){
if (printer == null) {
printer = new Printer(); // Printer μΈμ€ν΄μ€ μμ±
}
return printer;
}
public void print(String str) {
// μ€μ§ νλμ μ€λ λλ§ μ κ·Όμ νμ©ν¨ (μκ³ κ΅¬μ)
// μ±λ₯μ μν΄ νμν λΆλΆλ§μ μκ³ κ΅¬μμΌλ‘ μ€μ νλ€.
synchronized(this) {
counter++;
System.out.println(str + counter);
}
}
}
μΈμ€ν΄μ€λ₯Ό λ§λλ λ©μλλ₯Ό μκ³ κ΅¬μμΌλ‘ λ³κ²½
-
λ€μ€ μ€λ λ νκ²½μμ λμμ μ¬λ¬ μ€λ λκ° getPrinter λ©μλλ₯Ό μμ νλ κ°μ²΄μ μ κ·Όνλ κ²μ λ°©μ§νλ€. 곡μ λ³μμ μ κ·Όνλ λΆλΆμ μκ³ κ΅¬μμΌλ‘ λ³κ²½
-
μ¬λ¬ κ°μ μ€λ λκ° νλλΏμΈ counter λ³μ κ°μ λμμ μ κ·Όν΄ κ°±μ νλ κ²μ λ°©μ§νλ€. getInstance()μ Lockμ νλ λ°©μμ΄λΌ μλκ° λ리λ€.
κ²°λ‘ :
- Initialization on demand holder idiom (holderμ μν μ΄κΈ°ν)
μ΄ λ°©λ²μ ν΄λμ€μμ ν΄λμ€(Holder)λ₯Ό λμ΄ JVMμ Class Loader 맀컀λμ¦κ³Ό Classκ° λ‘λλλ μμ μ μ΄μ©ν λ°©λ²μ λλ€. Lazy initialization λ°©μμ κ°μ Έκ°λ©΄μ Threadκ° λκΈ°νλ¬Έμ λ₯Ό λμμ ν΄κ²°ν μ μμ΅λλ€.
μ€μ²©ν΄λμ€ Holderλ getInstance λ©μλκ° νΈμΆλκΈ° μ μλ μ°Έμ‘° λμ§ μμΌλ©°, μ΅μ΄λ‘ getInstance() λ©μλκ° νΈμΆ λ λ ν΄λμ€ λ‘λμ μν΄ μ±κΈν€ κ°μ²΄λ₯Ό μμ±νμ¬ λ¦¬ν΄ν©λλ€. μ°λ¦¬κ° μμλ¬μΌ ν κ²μ holder μμ μ μΈλ instanceκ° staticμ΄κΈ° λλ¬Έμ ν΄λμ€ λ‘λ© μμ μ νλ²λ§ νΈμΆλλ€λ μ μ μ΄μ©νκ²μ΄μ£ . λ finalμ μ¨μ λ€μ κ°μ΄ ν λΉλμ§ μλλ‘ ν©λλ€.
public class InitializationOnDemandHolderIdiom {
private InitializationOnDemandHolderIdiom(){}
private static class SingleTonHolder{
private static final InitializationOnDemandHolderIdiom instance = new InitializationOnDemandHolderIdiom();
}
public static InitializationOnDemandHolderIdiom getInstance(){
return SingleTonHolder.instance;
}
}