Singleton
Singleton ๊ด๋ จ
Singleton ์ ๊ฐ์ฒด ์์ฑ์ ์ ํ์ํค๋ ๋ชฉ์ ์ธ์๋ ์ง์ฐ ์ด๊ธฐํ(lazy initializaion) ๋ชฉ์ ๋ ์๋ค.
๊ธฐ๋ณธ ์ฝ๋
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null)
instance = new Singleton();
return instance;
}
}
private
์์ฑ์๋ก ์ธ๋ถ์์ Singleton ๊ฐ์ฒด๋ฅผ ์์ฑํ์ง ๋ชปํ๊ฒ ๋ง๊ณ getInstance()
๋ฉ์๋๋ฅผ ํตํด์๋ง ์ ๊ณตํ๋ค. getInstance()
์์๋ instance ๊ฐ null
์ผ๋๋ง ์์ฑํ๋๋ก ํด ๊ฐ์ฒด ์์ฑ์ ์ ํ์ํจ๋ค.
ํ์ง๋ง ์ด ๋ฐฉ์์ผ๋ก ๋ฉํฐ์ค๋ ๋ ํ๊ฒฝ์์ ๋๋ฆฌ๊ฒ ๋๋ฉด race condition ๋๋ฌธ์ ์ ๋๋ก ๋์ํ์ง ์์ ๊ฐ๋ฅ์ฑ์ด ์๋ค. ์ค๋ ๋ A์ ์ค๋ ๋ B๊ฐ ๋์์ getInstance()
๋ฅผ ์ํํ๋ค๊ณ ์น์. instance
๋ณ์๊ฐ null
์ด๋ผ๋ ์ฌ์ค์ ๋ณธ ๋ค์ ์ค๋ ๋ A๋ ์ธ์คํด์ค๋ฅผ ์๋ก ์์ฑํ๋ค. ์ค๋ ๋ B๋ instance
๋ณ์๊ฐ null
์ธ์ง ์ดํด๋ณธ๋ค. ์ด๋ instance
๋ณ์์ null
์ฌ๋ถ๋ ์ค์ผ์ค์ด ์ด๋ป๊ฒ ๋ณ๊ฒฝ๋ ์ง ๋๋ ์ค๋ ๋ A๊ฐ ์ธ์คํด์ค๋ฅผ ์์ฑํ๊ณ instance ๋ณ์์ ์ ์ฅํ๊ธฐ๊น์ง ์ผ๋ง๋ ๊ฑธ๋ฆฌ๋์ง ๋ฑ์ ์์ธกํ๊ธฐ ์ด๋ ค์ด ํ์ด๋ฐ์ ๋ฐ๋ผ ๋ฌ๋ผ์ง๋ค. ์๋ getInstance()
๋ ํญ์ ๊ฐ์ ์ธ์คํด์ค๋ฅผ ๋ฆฌํดํ๋๋ก ์ค๊ณ๋ผ ์๋๋ฐ, ์ค๋ ๋ B๊ฐ ์ดํด๋ณด๋ ๊ทธ ์์ ์ instance
๋ณ์๊ฐ null์ด๋ฉด getInstance()
๋ฅผ ํธ์ถํ ๋ ์ค๋ ๋๊ฐ ๊ฐ์ ์๋ก ๋ค๋ฅธ ์ธ์คํด์ค๋ฅผ ๊ฐ์ ธ๊ฐ ์๋ ์๋ค.
๋ฉํฐ์ค๋ ๋ ํ๊ฒฝ์์๋ ํ๋๋ง ์์ฑ๋๊ฒ ํ๋ ค๋ฉด?
๋ฐฉ๋ฒ1 synchronized
๋จ์์ถ๊ฐ
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static synchronized Singleton getInstance() {
if (instance == null)
instance = new Singleton();
return instance;
}
}
๊ฐ์ฅ ์ฝ๊ฒ ์๊ฐ๋๋๊ฑด getInstance
๋ฉ์๋์ synchronized
๋ฅผ ๋ถ์ด๋ ๊ฑฐ๋ค. ํ์ง๋ง race condition ์ ํผํ์ง๋ง ๋ค๋ฅธ ๋ถ์ ์ ์ธ ์ํฉํธ๊ฐ ๋ฐ์ํ๋ค. getInstance
๋ฉ์๋์ ๋ํ ๋ชจ๋ ํธ์ถ์ ๋๊ธฐํ ์ค๋ฒํค๋๋ฅผ ๊ฐ๊ฒ ๋๋ค. ์ฌ์ค race condition ๊ฐ๋ฅ์ฑ์ ๋จ์ง instance
๋ ํผ๋ฐ์ค๊ฐ ์ฒ์ ํ ๋น๋๋ ๊ฒฝ์ฐ์๋ง ๋ฐ์ํ๊ธฐ ๋๋ฌธ์ ๋ฐ์ํ ๋น๋๊ฐ ๋งค์ฐ ๋ฎ๋ค. ๋ฐ๋ผ์ ๋๊ธฐํ ๋ฐฉ๋ฒ์ด ์คํ๋ ค ์ค๋ฒํค๋๊ฐ ํฐ ๋ฐฉ๋ฒ์ด๋ค.
๋ฐฉ๋ฒ2 ์ฑ์ง ๊ธํ ์ด๊ธฐํ
์ฑ์ง ๊ธํ ์ด๊ธฐํ ๋ฐฉ๋ฒ์ static
๊ตฌ๋ฌธ์์ ์ด๊ธฐํํจ์ผ๋ก์จ ์์ฑ๋ ๋๋ ์ฐธ์กฐ๋ ๋ ๋ฐ๋ก ๋๊ธฐํ๋ฅผ ๋ง์ถ ํ์์๊ฒ ํ๋ค.
static
์ผ๋ก ์ ์ธ๋ ์ด๊ธฐํ ๋ฌธ์ฅ์ JVM ์์ ํด๋น ํด๋์ค๋ฅผ ์ฝ์ด๋ค์ด๊ณ ์ค์ ํด๋น ํด๋์ค๋ฅผ ์ฌ์ฉํ๊ธฐ ์ ์ ์คํ๋๋ค. ์ด๋ฐ ์ด๊ธฐํ ๊ณผ์ ์์ JVM์ด ๋ฝ์ ํ๋ณดํ๋ฉฐ ๊ฐ ์ค๋ ๋์์ ํด๋น ํด๋์ค๊ฐ ์ฝํ์ ธ ์๋์ง๋ฅผ ํ์ธํ๊ธฐ ์ํด ๋ฝ์ ๋ค์ ํ๋ณดํ๊ฒ ๋ผ ์๋ค. ๋ฐ๋ผ์ JVM์ด ๋ฝ์ ํ๋ณดํ ์ํ์์ ๋ฉ๋ชจ๋ฆฌ์ ์ฐ์ฌ์ง ๋ด์ฉ์ ๋ชจ๋ ์ค๋ ๋๊ฐ ๋ณผ ์ ์๋ค.
// ์๋ฐ ๋ณ๋ ฌ ํ๋ก๊ทธ๋๋ฐ p501
public class Singleton {
private static Singleton instance = new Singleton();
public static Singleton getInstance() {
return instance;
}
}
๋จ ์ด ๋ฐฉ๋ฒ์ ์ด๊ธฐํํ ๊ฐ์ฒด์ ๋ด์ฉ์ด ๊ทธ๋๋ก์ธ ์ํ๋ฅผ ๊ฐ์ ํ ๋๋ง ์ฑ๋ฆฝํ๋ค.
๋ฐฉ๋ฒ3 ๋ฆ์ ์ด๊ธฐํ ํ๋ ํด๋์ค
// ์๋ฐ ๋ณ๋ ฌ ํ๋ก๊ทธ๋๋ฐ p502
public class ResourceFactory {
private static class ResourceHolder {
public static Resource resource = new Resource();
}
public static Resource getResource() {
return ResourceHolder.resource;
}
}
์ค๋ก์ง Resource
ํด๋์ค๋ฅผ ์ด๊ธฐํํ ๋ชฉ์ ์ผ๋ก ๋ฆ์ ์ด๊ธฐํ ํ๋ ํด๋์ค ๊ตฌ๋ฌธ์ ์ ์ฉํด ์์ฑํ ํด๋์ค๋ค. JVM์ ResourceHolder
ํด๋์ค๋ฅผ ์ค์ ๋ก ์ฌ์ฉํ๊ธฐ ์ ๊น์ง๋ ํด๋น ํด๋์ค๋ฅผ ์ด๊ธฐํํ์ง ์์ผ๋ฉฐ, Resource
ํด๋์ค ์ญ์ static ์ด๊ธฐํ ๊ตฌ๋ฌธ์์ ์ด๊ธฐํํ๊ธฐ ๋๋ฌธ์ ์ถ๊ฐ์ ์ธ ๋๊ธฐํ ๊ธฐ๋ฒ์ ์ ์ฉํ ํ์๊ฐ ์๋ค. ์ด๋ ์ค๋ ๋๊ฑด ๊ฐ์ ์ฒ์ getResource()
๋ฉ์๋๋ฅผ ํธ์ถํ๋ฉด JVM์์ ResourceHolder
ํด๋์ค๋ฅผ ์ฝ์ด๋ค์ฌ ์ด๊ธฐํํ๊ณ , ResourceHolder
ํด๋์ค๋ฅผ ์ด๊ธฐํํ๋ ๋์ค์ Resource
ํด๋์ค ์ญ์ ์ด๊ธฐํํ๊ฒ ๋ผ ์๋ค.
(์ดํํฐ๋ธ ์๋ฐ item83) '์ง์ฐ ์ด๊ธฐํ๋ ์ ์คํ ์ฌ์ฉํ๋ผ' ์์๋ ์์ ๋ฐฉ์์ ์ถ์ฒํ๋ค. '์ฑ๋ฅ ๋ฌธ์ ๋๋ฌธ์ ์ ์ ํ๋ ์ด๊ธฐํ๋ฅผ ์ง์ฐ์ํค๊ณ ์ถ์ ๋๋ ์ด๊ธฐํ ์ง์ฐ ๋ด๋น ํด๋์ค(lazy initialization holder class) ์์ด๋ฅผ ์ ์ฉํ๋ผ' ๋ผ๊ณ ๋์ด์๋ค.
// ์ดํํฐ๋ธ์๋ฐ ์์ดํ
83
private static class FieldHolder {
static final FieldType field = computeFieldValue();
}
private static FieldType getField() { return FieldHolder.field; }
์ด ์์ด๊ฐ ์ข์ ์ ์ getField
๋ฅผ ๋๊ธฐํ ๋ฉ์๋๋ก ์ ์ธํ์ง ์์๋ ๋๋ค๋ ๊ฒ์ด๋ค. ๋ฐ๋ผ์ ์ด๊ธฐํ๋ฅผ ์ง์ฐ์์ผ๋ ๋ฉ์๋ ์ด์ฉ ๋น์ฉ์ ์ ํ ์ฆ๊ฐํ์ง ์๋๋ค. ์ต์ VM์ ํด๋์ค๋ฅผ ์ด๊ธฐํํ๊ธฐ ์ํ ํ๋ ์ ๊ทผ์ ๋๊ธฐํํ๋ค. ํ์ง๋ง ํด๋์ค๊ฐ ์ผ๋จ ์ด๊ธฐํ๋๊ณ ๋๋ฉด ์ฝ๋๋ฅผ ๋ฐ๊ฟ์ ์์ผ๋ก์ ํ๋ ์ ๊ทผ์๋ ์ด๋ค ๋๊ธฐํ๋ ๊ฒ์ฌ๋ ํ์์น ์๋๋ก ๋ง๋ ๋ค.
๋ฐฉ๋ฒ4 Supplier ์ฌ์ฉ
์๋ฐ8์์ ์ถ๊ฐ๋ FunctionalInterface Supplier<T>
๋ฅผ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ด๋ค.
// Functional Programming in Java8
public class Holder {
private Supplier<Heavy> heavy = () -> createAndCacheHeavy();
public Holder() {
System.out.println("Holder created");
}
public Heavy getHeavy() {
return heavy.get();
}
//...
private synchronized Heavy createAndCacheHeavy() {
class HeavyFactory implements Supplier<Heavy> {
private final Heavy heavyInstance = new Heavy();
public Heavy get() { return heavyInstance; }
}
if(!HeavyFactory.class.isInstance(heavy)) {
heavy = new HeavyFactory();
}
return heavy.get();
}
}
final Holder holder = new Holder();
holder.getHeavy();
Holder์ ์ธ์คํด์ค๊ฐ ์์ฑ๋ ๋ Heavy์ ์ธ์คํด์ค๋ ์์ฑ๋์ง ์๋๋ค. ๊ทธ๋ฆฌ๊ณ ์ฒ์ holder.getHeavy()
๊ฐ ํธ์ถ๋๋ฉด ๊ทธ ์์ heavy
๋ ๊ธฐ๋ณธ Supplier<Heavy>
type ์ด๊ธฐ ๋๋ฌธ์ Supplier
๊ตฌํ์ฒด๊ฐ ์คํ๋๋ค. ๋ฐ๋ผ์ createAndCacheHeavy()
๋ฉ์๋๊ฐ ์คํ๋๊ณ , heavy
๋ HeavyFactory
๊ฐ ์๋๋ฏ๋ก ์๋กญ๊ฒ HeavyFactory
๊ฐ์ฒด๋ฅผ ๋ง๋ ๋ค. ๊ทธ๋ฆฌ๊ณ HeavyFactory
์์ Heavy
๊ฐ์ฒด๋ฅผ ๋ง๋ค๊ณ get()
๋ฉ์๋๋ฅผ ํตํด ์ ๊ณตํ๋ค.
๊ทธ ์ดํ๋ถํฐ๋ heavy
๊ฐ HeavyFactory
ํ์
์ด๊ธฐ ๋๋ฌธ์ getHeavy()
๋ฉ์๋๋ฅผ ํธ์ถํ์ ๋ ๋ฐ๋ก heavyInstace()
๋ฅผ ๊ฐ์ ธ์ค๊ฒ ๋๋ค. ์ฒ์ ๊ฐ์ฒด ์์ฑํ ๋๋ง synchronized
๋ถ๋ถ์ผ๋ก ๋ณดํธ๋ฐ๊ณ ์์ฑ ํ ํธ์ถ์ ๋ค๋ฅด๊ฒ ์ ๊ทผํ์ฌ ๋๊ธฐํ ์ค๋ฒํค๋๋ ๋ฐ์์ํค์ง ์๋๋ค.
๋ฐฉ๋ฒ5 enum
// ์ดํํฐ๋ธ์๋ฐ item3
public enum EnumSingleton {
INSTANCE;
public static EnumSingleton getInstance() {
return INSTANCE;
}
}
์ด์ ๋ฐฉ์์ ๋นํด ๋ ๊ฐ๊ฒฐํ๊ณ , ์ง๋ ฌํ๊ฐ ์๋์ผ๋ก ์ฒ๋ฆฌ๋๋ค. ๋ฆฌํ๋ ์
์ ํตํ ๊ณต๊ฒฉ์๋ ์์ ํ๋ค. ์์๊ฐ ํ๋๋ฟ์ธ enum
์๋ฃํ์ด์ผ๋ง๋ก Singleton
์ ๊ตฌํํ๋ ๊ฐ์ฅ ์ข์ ๋ฐฉ๋ฒ์ด๋ค.
Singleton ๋จ์
1. ํด๋์ค๋ฅผ Singleton ์ผ๋ก ๋ง๋ค๋ฉด ํด๋ผ์ด์ธํธ๋ฅผ ํ ์คํธํ๊ธฐ๊ฐ ์ด๋ ค์์ง ์๊ฐ ์๋ค.
Singleton ์ด ์ด๋ค ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ๋ ๊ฒ์ด ์๋๋ฉด ๊ฐ์ง ๊ตฌํ์ผ๋ก ๋์ฒดํ ์ ์๊ธฐ ๋๋ฌธ์ด๋ค.
2. ๋ฆฌํ๋ ์
๊ธฐ๋ฅ์ ํตํด private
์์ฑ์๋ฅผ ํธ์ถํ๋ ๊ณต๊ฒฉ์ ๋ฐ์ ์ ์๋ค.
AccessibleObject.setAccessible
๋ฉ์๋์ ๋์์ ๋ฐ์ ๊ถํ ํ๋์ด ๊ฐ๋ฅํ๋ค.
Constructor<?> con = Private.class.getDeclaredConstructors()[0];
con.setAccessible(true);
Private p = (Private) con.newInstance();
3. Singleton ํด๋์ค๋ฅผ ์ง๋ ฌํ ๊ฐ๋ฅ(Serializable
) ํด๋์ค๋ก ๋ง๋๋ ค๋ฉด ํด๋์ค ์ ์ธ์ implements Serializable
์ ์ถ๊ฐํ๋ ๊ฒ์ผ๋ก๋ ๋ถ์กฑํ๋ค.
(์ดํํฐ๋ธ ์๋ฐ item89) Singleton ํน์ฑ์ ์ ์งํ๋ ค๋ฉด ๋ชจ๋ ํ๋๋ฅผ transient
๋ก ์ ์ธํ๊ณ readResolve()
๋ฉ์๋๋ฅผ ์ถ๊ฐํด์ผ ํ๋ค. ๊ทธ๋ ์ง ์์ผ๋ฉด ์ง๋ ฌํ๋ ๊ฐ์ฒด๊ฐ ์ญ์ง๋ ฌํ๋ ๋๋ง๋ค ์๋ก์ด ๊ฐ์ฒด๊ฐ ์๊ธฐ๊ฒ๋๋ค.
public class Elvis implements Serializable {
public static final Elvis INSTANCE = new Elvis();
private Elvis() { ... }
// Singleton ์ํ๋ฅผ ์ ์งํ๊ธฐ ์ํ readResolve ๊ตฌํ
private Object readResolve() {
// ๋์ผํ Elvis ๊ฐ์ฒด๊ฐ ๋ฐํ๋๋๋ก ํ๋ ๋์์, ๊ฐ์ง Elvis ๊ฐ์ฒด๋ GC๊ฐ ์ฒ๋ฆฌํ๋๋ก ๋ง๋ ๋ค.
return INSTANCE;
}
}
์ญ์ง๋ ฌํํ ๊ฐ์ฒด์ ํด๋์ค์ ์ ๋๋ก ์ ์ธ๋ readResolve()
๋ฉ์๋๊ฐ ์ ์๋์ด ์๋ ๊ฒฝ์ฐ, ์ญ์ง๋ ฌํ๊ฐ ๋๋์ ๋ง๋ค์ด์ง ๊ฐ์ฒด์ ๋ํด ์ด ๋ฉ์๋๊ฐ ํธ์ถ๋๋ค.
4. private
์์ฑ์๋ฅผ ๊ฐ๊ณ ์๊ธฐ ๋๋ฌธ์ ์์ํ ์ ์๋ค.
(ํ ๋น ์คํ๋ง) ๊ธฐ์ ์ ์ธ ์๋น์ค๋ง ์ ๊ณตํ๋ ๊ฒฝ์ฐ๋ผ๋ฉด ์๊ด์๊ฒ ์ง๋ง, ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ก์ง์ ๋ด๊ณ ์๋ ์ผ๋ฐ ์ค๋ธ์ ํธ์ ๊ฒฝ์ฐ Singleton ์ผ๋ก ๋ง๋ค์์ ๋ ๊ฐ์ฒด์งํฅ์ ์ธ ์ค๊ณ์ ์ฅ์ ์ ์ ์ฉํ๊ธฐ๊ฐ ์ด๋ ต๋ค๋ ์ ์ ์ฌ๊ฐํ ๋ฌธ์ ๋ค.
5. ์๋ฒํ๊ฒฝ์์๋ Singleton
์ด ํ๋๋ง ๋ง๋ค์ด์ง๋ ๊ฒ์ ๋ณด์ฅํ์ง ๋ชปํ๋ค.
(ํ ๋น ์คํ๋ง) ์๋ฒ์์ ํด๋์ค ๋ก๋๋ฅผ ์ด๋ป๊ฒ ๊ตฌ์ฑํ๊ณ ์๋๋์ ๋ฐ๋ผ์ Singleton ํด๋์ค์์๋ ํ๋ ์ด์ ์ ์ค๋ธ์ ํธ๊ฐ ๋ง๋ค์ด์ง ์ ์๋ค. ์ฌ๋ฌ ๊ฐ์ JVM์ ๋ถ์ฐ๋ผ์ ์ค์น๊ฐ ๋๋ ๊ฒฝ์ฐ์๋ ๊ฐ๊ฐ ๋ ๋ฆฝ์ ์ผ๋ก ์ค๋ธ์ ํธ๊ฐ ์๊ธฐ๊ธฐ ๋๋ฌธ์ Singleton ์ผ๋ก์์ ๊ฐ์น๊ฐ ๋จ์ด์ง๋ค.
6. Singleton ์ ์ฌ์ฉ์ ์ ์ญ ์ํ๋ฅผ ๋ง๋ค ์ ์๊ธฐ ๋๋ฌธ์ ๋ฐ๋์งํ์ง ๋ชปํ๋ค.
(ํ ๋น ์คํ๋ง) Singleton ์ ์ฌ์ฉํ๋ ํด๋ผ์ด์ธํธ๊ฐ ์ ํด์ ธ ์์ง ์๋ค. Singleton ์ ์คํํฑ ๋ฉ์๋๋ฅผ ์ด์ฉํด ์ธ์ ๋ ์ง Singleton ์ ์ฝ๊ฒ ์ ๊ทผํ ์ ์๊ธฐ ๋๋ฌธ์ ์ ํ๋ฆฌ์ผ์ด์ ์ด๋์๋ ์ง ์ฌ์ฉ๋ ์ ์๊ณ , ๊ทธ๋ฌ๋ค ๋ณด๋ฉด ์์ฐ์ค๋ฝ๊ฒ ์ ์ญ ์ํ๋ก ์ฌ์ฉ๋๊ธฐ ์ฝ๋ค. ์๋ฌด ๊ฐ์ฒด๋ ์์ ๋กญ๊ฒ ์ ๊ทผํ๊ณ ์์ ํ๊ณ ๊ณต์ ํ ์ ์๋ ์ ์ญ ์ํ๋ฅผ ๊ฐ๋ ๊ฒ์ ๊ฐ์ฒด์งํฅ ํ๋ก๊ทธ๋๋ฐ์์๋ ๊ถ์ฅ๋์ง ์๋ ํ๋ก๊ทธ๋๋ฐ ๋ชจ๋ธ์ด๋ค.