2-3 Singleton (์ฑ๊ธํค ํจํด)
by JiwonDev# ์ฑ๊ธํค ํจํด
ํ๋ก์ธ์ค์ ๊ฐ์ฒด์ ์ธ์คํด์ค๊ฐ ๋จ ํ๋๋ง ์กด์ฌํ๋๋ก ๋ง๋๋ ํจํด.
โญ Static ๋ฉ๋ชจ๋ฆฌ ์์ญ์ ๊ฐ์ฒด๋ฅผ ํ๋๋ง ์์ฑ, ์ฌ์ฌ์ฉํจ์ผ๋ก์ ๋ฉ๋ชจ๋ฆฌ ๋ญ๋น๋ฅผ ๋ฐฉ์งํ๋ค.
โญ ๊ฐ์ฒด๋ฅผ ์๋ก ์์ฑํ์ง ์๊ณ , ๊ธฐ์กด์ ๊ฐ์ฒด๋ฅผ ์ฌ์ฌ์ฉํจ์ผ๋ก์ ๋ก๋ฉ ์๊ฐ์ ์ค์ฌ ์ฑ๋ฅ์ ํฅ์์ํจ๋ค.
โ (์ํฐ ํจํด) ์ฑ๊ธํค ๊ฐ์ฒด๊ฐ ์ํ ๊ฐ์ ๊ฐ์ง ๊ฒฝ์ฐ ์ ๋ง ์ฐพ๊ธฐ ํ๋ Side-Effect์ ์ฅ์ ๋ฅผ ๋ง๋ค ์ ์๋ค.
โ ๋ฉํฐ์ค๋ ๋ ํ๊ฒฝ์์ ์ ์ ํ ๋๊ธฐํ ์ฒ๋ฆฌ๋ฅผ ํ์ง ์์ผ๋ฉด, ์ฑ๊ธํค ์ธ์คํด์ค๊ฐ 2๊ฐ๊ฐ ์๊ธธ ๊ฐ๋ฅ์ฑ์ด ์๋ค.
# ์ฑ๊ธํค ํจํด์ ๊ตฌํ
@1. ์ฆ์ ๋ก๋ฉ (Eager initialization)
โก ๊ฐ์ฅ ๋จ์ํ ๋ฐฉ๋ฒ์ด๋ค. private static final ์ ์ฌ์ฉํด์, ํด๋์ค๊ฐ JVM์ ์ฝํ์ง ๋ ๊ฐ์ฒด๊ฐ ๋ง๋ค์ด์ง๋๋ก ํ๋ค.
โ ํด๋์ค๊ฐ ์์ฑ๋๋ ์์ ์ ์ด๋ ํ ์์ธ ์ฒ๋ฆฌ๋ ํ ์ ์๋ค. ๋๊ฐํ๋ค.
โ ์ฑ๊ธํค ๊ฐ์ฒด๋ฅผ ์ ํ ์ฌ์ฉํ์ง ์์๋, ํด๋์ค ๋ก๋ฉ ์์ ์ ์ธ์คํด์ค๊ฐ ์์ฑ ๋์ด์๋ค..
public class Singleton {
private static final Singleton instance = new Singleton();
// ์์ฑ์๋ฅผ ์ฌ์ฉ ๋ชปํ๊ฒ ๋ง์๋ฒ๋ฆฐ๋ค.
private Singleton() {}
// ํ์ํ๋ฉด getInstance()๋ฅผ ์ด์ฉํ์ฌ ๊ฐ์ ธ์จ๋ค.
public static Singleton getInstance() {
return instance;
}
}
@2. ์ง์ฐ ๋ก๋ฉ (Lazy initialization)
โก ๊ทธ๋ฌ๋ฉด ์ฌ์ฉํ๋ ์์ ์ ์ธ์คํด์ค๋ฅผ ์์ฑํ๋ฉด ๋๋๊ฑฐ ์๋๊น?
โ ๋ฉํฐ ์ค๋ ๋์์ ๋๊ธฐํ ๋์ง ์๋๋ค. ์ฆ ๋์์ getInstance()๋ฅผ ํธ์ถํด์ ์ธ์คํด์ค๊ฐ 2๊ฐ๊ฐ ๋ง๋ค์ด ์ง ์ ์๋ค.
public class LazyInitialization {
private static LazyInitialization instance;
private LazyInitialization() {}
public static LazyInitialization getInstance() {
if (instance == null) { // getInstance()์ ํธ์ถ ์์ ์ ์์ฑํจ.
instance = new LazyInitialization();
}
return instance;
}
}
@3. Thread Safe, Double checked Locking
โก ์ ๋ฉํฐ ์ค๋ ๋์ผ ๋ญ, synchronzied ๋ถ์ด๋ฉด ๋๋๊ฑฐ์์?
โ getInstance()๋ฅผ ํธ์ถํ ๋ ๋ง๋ค synchronzied ๋๋ฌธ์ ์ค๋ ๋๊ฐ ๋ธ๋ก๋๋ค. ์ฑ๋ฅ์ด ํฌ๊ฒ ๋จ์ด์ง๋ค.
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
โก ์๋ ๋งค๋ฒ ๋ธ๋กํ๋ค๋๊ฒ ์๋๋ผ ์กฐ๊ฑด๋ฌธ ๋ฌ์์ ์ฒซ ์์ฑ๋๋ง synchronzied๋ฅผ ํ์๊ตฌ!
โ if (null) ์ผ ๋๋ง ์ค๋ ๋ ๋ธ๋ก์ ํ๋ค๊ณ ํ๋ค ๋ด๋ถ์์ ๋น๊ต๋ฅผ 2๋ฒ (Double Check) ํด์ค์ผํ๊ณ ์ฑ๋ฅ๋ ์ฌ์ ํ ์์ข๋ค.
public static Singleton getInstance(){
if(instance == null){
synchronized (Singleton.class) {
if(instance == null){
instance = new Singleton();
} // synchronized
} // check - null
} // double check - null
return instance;
}
@4. Lazy Holder ๋ฐฉ๋ฒ (Bill Pugh's Singleton Implementation)
๋ฏธ๊ตญ ๋ฉ๋ฆด๋๋ ๋ํ ์ฐ๊ตฌ์์ธ Bill pugh๊ฐ ์ ์ํ ๋ฐฉ๋ฒ์ด๋ค.
๋ด๋ถ ํด๋์ค์์ static์ผ๋ก ์์ฑํ์ฌ ๋ฉํฐ์ค๋ ๋์ ์์ ์ ๋ณด์ฅํ๊ณ , ์์ฑ์์ ์ ํธ์ถ์ง์ ์ผ๋ก ๋ฏธ๋ฃจ๋ ๋ฐฉ๋ฒ.
public class Singleton {
private Singleton(){}
// ๊ฐ์ฒด ์์ฑ์ ๋ด๋ถํด๋์ค(Lazyholder)์์ static์ผ๋ก ๋ง๋ ๋ค.
private static class LazyHolder{
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance(){
return LazyHolder.INSTANCE; // ์ธ๋ถ ํด๋์ค์์ ์ฌ์ฉํ๋ค.
}
}
์ด? ์ด๋ ๊ฒํ๋ฉด @2. ์ ๊ฐ์๊ฑฐ ์๋๊ฐ ์ถ์ง๋ง JVM์ ๋์๊ณผ์ ์ ์ดํดํ๋ฉด ํฐ ์ฐจ์ด๊ฐ ์์์ ์ ์ ์๋ค.
- ์๋ฐ์ Static์์ญ์ JVM์ ํด๋์ค๋ก๋๊ฐ [ .Class ] ๋ฅผ ์ฝ์ ๋ ์์ฑ๋๊ณ ์ด๊ธฐํ ๋๋ค.
- JVM์ ํด๋์ค๋ก๋๋ Lazyํ๊ฒ ๋์ํ๋ค. ์ฆ ์ฌ๋ณผ๋ฆญ ์ฐธ์กฐ๊ฐ๋ง ๊ฐ์ง๊ณ ์๋ค๊ฐ, ์ฌ์ฉ๋๋ ์์ ์ ํด๋์ค๋ฅผ ์ฝ๋๋ค.
- [@4. LazyHolder] ๋ฅผ ์ฌ์ฉํ๋ฉด ์ธ๋ถํด๋์ค๋ ๋ฐ๋ก ์ฝํ์ง๋ง ๋ด๋ถ ํด๋์ค๋ ์ฌ์ฉํ๋ ์์ ๊น์ง ๋ก๋ฉ์ด ๋ฆ์ถฐ์ง๋ค.
โญ JVM์ ์ต์ ํ์ ๋ฐ๋ผ ๋ค๋ฅด๊ฒ ์ง๋ง, ๋๋ถ๋ถ ์ฌ์ฉํ๊ธฐ ์ง์ ๊น์ง ๊ฐ์ฒด ์์ฑ์ ๋ฆ์ถ ์ ์๋ค.
โญ ๊ฒ๋ค๊ฐ static์ ์ด์ฉํ ์ด๊ธฐํ์ด๊ธฐ์ ๋ฉํฐ์ค๋ ๋์ ์์ ํ๊ณ , ๋ด๋ถ ํด๋์ค์์ ์์ธ์ฒ๋ฆฌ๋ ๊ฐ๋ฅํ๋ค.
// ์ฐธ์กฐ ๊ฐ๋ง ๊ฐ์ง๊ณ ์์ ๋ฟ, ์์ง ๋ด๋ถ ํด๋์ค๋ฅผ ์ฌ์ฉํ์ง ์์๋ค.
var mySingleton = Singleton.getInstance(); // ์ฆ ์์ง ๊น์ง ๋ด๋ถ ํด๋์ค๋ ์ฝํ์ง์ง ์์์.
/* ... other code ... */
mySingleton.method() // ์ด ์์ ์ LazyHolder๊ฐ ์ฝํ์ง๊ณ , Static์์ญ์ด ์ด๊ธฐํ ๋๋ค.
@5. ๋ฆฌํ๋ ์ ๋ฐฉ์ด - Enum
์ค์ ์๋น์ค์์ ๊ฐ์ฅ ๋ง์ด ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ @4.์ด๋ค.
๋ค๋ง [@1~@4]๋ ์ ๋ถ ์๋ฐ์ ๋ฆฌํ๋ ์ (๋ฐ์ดํธ์ฝ๋ ์กฐ์)์ ์ฌ์ฉํ๋ ์๋น์ค๋ ๊ฐ๋ฐ์์ ์ค์๋ก ์ฑ๊ธํค์ด ๊นจ์ง ์ ์๋ค๋ ์ํ์ฑ์ด ์๋๋ฐ, Enum์ ์ฌ์ฉํ๋ฉด ๋ฐฉ์งํ ์ ์๋ค. โก ํ์ง๋ง ์ฑ๋ฅ์ด ๊ตฌ๋ ค์ ์ ์์ด๋ค.
public enum EnumInitialization {
INSTANCE;
static String test = "";
public static EnumInitialization getInstance() {
test = "test";
return INSTANCE;
}
}
// ๋ฆฌํ๋ ์
(๋ฐ์ดํธ์ฝ๋ ์กฐ์)๊น์ง ์ฌ์ฉํ๋ ์๋น์ค๋ผ๋ฉด, ์ด๋ ๊ฒ ํด๋ฒ๋ฆด ์ํ์ด ์๊ธดํ๋ค.
public class UsingReflectionToDestroySingleton {
public static void main (String[] args) {
EagerInitialization instance = EagerInitialization.getInstance();
EagerInitialization instance2 = null;
try {
Constructor[] constructors = EagerInitialization.class.getDeclaredConstructors();
for ( Constructor constructor : constructors ) {
constructor.setAccessible(true);
instance2 = (EagerInitialization)constructor.newInstance();
}
} catch (Exception e) {
}
System.out.println(instance.hashCode());
System.out.println(instance2.hashCode());
}
}
๋ธ๋ก๊ทธ์ ์ ๋ณด
JiwonDev
JiwonDev