Effective Java 3/E
μ μ ν©ν°λ¦¬ λ©μλμ public μμ±μλ κ°μμ μ°μμκ° μμΌλ μλμ μΈ μ₯λ¨μ μ μ΄ν΄νκ³ μ¬μ©νλ κ²μ΄ μ’κ² λ€. κ·Έλ λ€κ³ νλλΌλ μ μ ν©ν°λ¦¬λ₯Ό μ¬μ©νλκ² μ 리ν κ²½μ°κ° λ λ§μΌλ―λ‘ λ¬΄μμ public μμ±μλ₯Ό μ 곡νλ μ΅κ΄μ΄ μλ€λ©΄ κ³ μΉμ!
μμ΄ν 3: μμ±μλ μ΄κ±° νμ μΌλ‘ μ±κΈν΄μμ 보μ¦νλΌ
μ±κΈν΄?
μΈμ€ν΄μ€λ₯Ό μ€μ§ νλλ§ μμ±ν μ μλ ν΄λμ€
μ±κΈν΄μ λ§λλ λ°©μ
1. public static final νλ λ°©μ
2. static factory method λ°©μ
3. μμκ° 1κ°μΈ ENUM νμ
1. public static final νλ λ°©μμ μ±κΈν΄
μμ±μλ privateμΌλ‘ κ°μΆ°λκ³ , μ μΌν μΈμ€ν΄μ€μ μ κ·Όν μ μλ μλ¨μ public static final νλλ‘ μ ννλ€.
public static final νλ λ°©μμ κ°μ₯ ν° μ₯μ μ ν΄λΉ ν΄λμ€κ° μ±κΈν΄μμ΄ APIμ λͺ νν λλ¬λλ€λ μ μ΄λ€.
public class Singleton {
//μ΄κΈ°ν ν λ νλ²λ§ μ€μ λ¨μΌλ‘ νλμ μΈμ€ν΄μ€λ§μ 보μ₯ ν μ μμ
public static final Singleton INSTANCE = new Singleton();
// μμ±μλ₯Ό private μΌλ‘ μ μΈνμ¬ μΈλΆ ν΄λΌμ΄μΈνΈμμ μ κ·Ό λΆκ°λ₯
private Singleton() {
// 리νλ μ
λ°©μ΄ μ½λ
if(INSTANCE != null) {
throw new Exception("μμ± λΆκ°");
}
}
}
2. μ μ ν©ν°λ¦¬ λ©μλλ₯Ό public static 맴λ²λ‘ μ 곡
public class Singleton {
private static final Singleton INSTANCE = new Singleton();
private Singleton() { ... }
public static Singleton getInstance() {
return INSTANCE;
}
}
μ΄ λ°©μλ μλ° λ¦¬νλ μ μΌλ‘ μ κ·Όμ΄ κ°λ₯νλ public staitc fianl λ°©μκ³Ό κ°μ΄ μμΈμ²λ¦¬λ₯Ό ν΄μ€μΌνλ€.
API λ₯Ό λ³κ²½νμ§ μκ³ λ μ±κΈν΄ μ¬μ© μ¬λΆλ₯Ό λ³κ²½ν μ μλ€.
public class Singleton {
private static final Singleton INSTANCE = new Singleton();
private Singleton() {
}
public static Singleton getInstance(){
// ν΄λΉ λΆλΆλ§ λ³κ²½νμ¬ μ±κΈν€ μ¬μ©μ¬λΆλ₯Ό λ³κ²½κ°λ₯
return new Singleton();
}
}
μ μ ν©ν°λ¦¬μ λ©μλλ₯Ό Supplier<> μ λν λ©μλ λ νΌλ°μ€λ‘ μ¬μ©ν μ μλ€.
Supplier<Singleton> supplier = Singleton::getInstance;
Singleton instance = supplier.get();
μμ λ λ°©μ μ€ νλλ‘ λ§λ μ±κΈν΄ ν΄λμ€λ₯Ό μ§λ ¬ννλ €λ©΄ λ¨μν `Serializable`μ ꡬννλ€κ³ μ μΈνλ κ²λ§μΌλ‘ λΆμ‘±νλ€. λͺ¨λ μΈμ€ν΄μ€ νλλ₯Ό μΌμμ (transient)μ΄λΌ μ μΈνκ³ `readResolve` λ©μλλ₯Ό μ 곡ν΄μΌ νλ€. μ΄λ κ² νμ§ μμΌλ©΄ μ§λ ¬νλ μΈμ€ν΄μ€λ₯Ό μμ§λ ¬νν λλ§λ€ μλ‘μ΄ μΈμ€ν΄μ€κ° λ§λ€μ΄μ§λ€. μμ§λ ¬ν μ νΈμΆνλ μ¨κ²¨μ§ κΈ°λ³Έ `readResolve` ν¨μμμλ return new Objectλ₯Ό ν΄μ μλ‘μ΄ μΈμ€ν΄μ€κ° μμ±λλ€.
import java.io.Serializable;
public final class Singleton implements Serializable {
private static final Singleton INSTANCE = new Singleton();
private Singleton() {
}
public static Singleton getInstance() {
return INSTANCE;
}
// readResolve λ©μλλ₯Ό μ μνλ€.
private Object readResolve() {
// μ±κΈν΄μ 보μ₯νκΈ° μν¨
return INSTANCE;
}
}
3. μμκ° 1κ°μΈ ENUM νμ
첫 λ²μ§Έ public static final νλ λ°©μκ³Ό λΉμ·νμ§λ§ λ κ°κ²°νκ³ , μΆκ° λ Έλ ₯ μμ΄ μ§λ ¬ν κ°λ₯νλ©°, μμ£Ό 볡μ‘ν μ§λ ¬ν μν©μ΄λ 리νλ μ 곡격μμλ μ 2μ μΈμ€ν΄μ€κ° μκΈ°λ μΌμ μλ²½ν λ§μμ€λ€. μ΄ μ± μμ μμκ° νλλΏμΈ μ΄κ±°νμ μ΄ μ±κΈν΄μ λ§λλ κ°μ₯ μ’μ λ°©λ²μ΄λΌκ³ μκ°νκ³ μλ€. λ¨, λ§λ€λ €λ μ±κΈν΄μ΄ Enum μΈμ ν΄λμ€λ₯Ό μμν΄μΌ νλ€λ©΄ μ΄ λ°©μμ μ¬μ©ν μ μλ€.
public enum Singleton {
INSTANCE;
...
}
+ λ€μν μ±κΈν€ ꡬν λ°©μ
1. Eager Initialization (μ΄λ₯Έ μ΄κΈ°ν, Thread-safe)
- μμμ μκ°ν public static final νλ λ°©μμ΄λ€.
- μ ν리μΌμ΄μ μμ ν΄λΉ μΈμ€ν΄μ€λ₯Ό μ¬μ©νμ§ μλλΌλ μΈμ€ν΄μ€λ₯Ό μμ±νκΈ° λλ¬Έμ λλΉκ° λ°μν μ μλ€.
- μ±κΈν€ ν΄λμ€κ° λ€μ μ μ 리μμ€λ₯Ό λ€λ£° λ μ¬μ©νλ κ²μ΄ μ’λ€
2. static block initialization (μ μ λΈλ μ΄κΈ°ν, Thread-safe)
- Eager Initalization λ°©μμ Exception Handlingμ μΆκ°ν λ°©μμ΄λ€.
public class Singleton {
private static Singleton instance;
private Singleton(){}
static{
try{
instance = new Singleton();
}catch(Exception e){
throw new RuntimeException("Exception occured in creating singleton instance");
}
}
public static Singleton getInstance(){
return instance;
}
}
3. Lazy Initialization (κ²μΌλ₯Έ μ΄κΈ°ν)
- μμ λ λ°©μκ³Ό λ€λ₯΄κ² λμ€μ μ΄κΈ°ν νλ λ°©μμ΄λ€.
- Eager λ°©μμ μ¬μ©λμ§ μλ μΈμ€ν΄μ€λ₯Ό μμ±νλ€λ λ¬Έμ μ λν ν΄κ²°μ± μ΄ λ μ μλ€. νμ§λ§ λ©ν° μ°λ λ νκ²½μμ μΈμ€ν΄μ€κ° μμ±λμ§ μμ μμ μ μ¬λ¬ μ°λ λκ° λμμ getInstance() λ₯Ό νΈμΆνκ² λλ€λ©΄ λκΈ°ν λ¬Έμ κ° λ°μν μ°λ €κ° μλ€.
public class Singleton {
private static Singleton instance;
private Singleton(){}
public static Singleton getInstance(){
if(instance == null){
instance = new Singleton();
}
return instance;
}
}
4. Lazy Initialization with synchronized ( λκΈ°ν λΈλμ μ¬μ©ν κ²μΌλ₯Έ μ΄κΈ°ν, Thread-safe )
- 1,2 Eager λ°©μ, 3 Lazy Initialization λ°©μμ λ¨μ μ λͺ¨λ ν΄κ²°ν μ μλ€.
- synchronized ν€μλ μ체μ λν λΉμ©μ΄ ν¬κΈ° λλ¬Έμ μ±κΈν€ μΈμ€ν΄μ€ νΈμΆμ΄ μ¦μ μ ν리μΌμ΄μ μ λν΄μλ μ±λ₯μ΄ λ¨μ΄μ§κ² λλ€.
public class Singleton {
private static Singleton instance;
private Singleton(){}
public static synchronized Singleton getInstance(){
if(instance == null){
instance = new Singleton();
}
return instance;
}
}
5. Lazy Initialization, Double Checking Locking ( DCL, Thread-safe )
- 4λ²μ λ¬Έμ λ₯Ό ν΄κ²°νκΈ° μν΄ μΈμ€ν΄μ€κ° μμ±λμ΄ μμ§ μμ μμ μλ§ synchronizedκ° μ€νλκ²λ ꡬννλ λ°©μμ΄λ€.
public class Singleton {
private volatile static Singleton instance;
private Sigleton() {}
// Lazy Initialization. DCL
public Singleton getInstance() {
// 첫 λΆλΆμμ κ°μ²΄λ₯Ό λ§λ€μ΄μΌ νλ μ§λ₯Ό λ¨Όμ νμΈνκ³ κ°μ²΄λ₯Ό λ§λ€μ΄μΌ ν λλ§ λ½μ μ»μ΄μΌ νλλ‘ λ§λ€ μ μλ€.
if(instance == null) {
synchronized(Singleton.class) {
// μ°μ°μ μμμ±μ μ μ§νκΈ° μν΄μ λκΈ°ν λΈλ‘μ λ€μ΄κ°μλ§μ κ°μ νμΈ μμ
μ μνν μ μλ€.
if(instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
μ΄ ν¨ν΄μ μ¬μ©ν λλ λ°λμ νλλ₯Ό volatileλ‘ ν΄μΌ νλ€. volatile ν€μλλ₯Ό μ΄μ©ν΄μ μΊμ λΆμΌμΉ μ΄μλ₯Ό λ°©μ§ ν μ μλ€. μ€μ λ‘ μλ° λ©λͺ¨λ¦¬ λͺ¨λΈμ λΆλΆμ μΌλ‘ μ΄κΈ°ν λ κ°μ²΄μ λ°νμ νμ©νκΈ° λλ¬Έμ νμ νκΈ° μ΄λ €μ΄ λ²κ·Έλ₯Ό λ§λ€μ΄ λΌ μ μλ€.
6. Lazy initialization, LazyHolder ( κ²μΌλ₯Έ νλ, Thread-safe )
- inner static helper classλ₯Ό μ¬μ©νλ λ°©μμΈλ°, volatile μ΄λ synchronized ν€μλ μμ΄λ λμμ± λ¬Έμ λ₯Ό ν΄κ²°νκΈ° λλ¬Έμ μ±λ₯μ΄ λ°μ΄λλ©° νμ¬ κ°μ₯ λ리μ°μ΄λ μ±κΈν€ ꡬν λ°©μμ΄λ€.
public class Singleton {
private Singleton() {}
private static class InnerInstanceClazz {
// ν΄λμ€ λ‘λ© μμ μμ μμ±
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return InnerInstanceClazz.INSTANCE;
}
}
- private inner static classλ₯Ό λμ΄ μ±κΈν€ μΈμ€ν΄μ€λ₯Ό κ°κ² νλ€.
- InnerInstanceClazzν΄λμ€λ Singleton ν΄λμ€κ° Load λ λμλ λ‘λλμ§ μλ€κ° getInstanceκ° νΈμΆ λμμ λ JVM λ©λͺ¨λ¦¬μ λ‘λ λκ³ , μΈμ€ν΄μ€λ₯Ό μμ±νκ² λλ€.
7. Enum Singleton ( Thread-safe )
- μμ μ΄ν΄λ³Έ μμκ° 1κ°μΈ Enum λ°©μκ³Ό λμΌνλ€.