๐ก ์ฑ๊ธํค ํจํด (singleton pattern)
ํด๋น ํด๋์ค์ ์ธ์คํด์ค๊ฐ ํ๋๋ง ๋ง๋ค์ด์ง๊ณ , ์ด๋์๋ ์ง ๊ทธ ์ธ์คํด์ค์ ์ ๊ทผํ ์ ์๋๋ก ํ๊ธฐ์ํ ํจํด
ํด๋์ค์์ ์์ ์ ๋จ ํ๋๋ฟ์ธ ์ธ์คํด์ค๋ฅผ ๊ด๋ฆฌํ๋๋ก ๋ง๋๋ ๊ฒ์ด๋ค.
๋ค๋ฅธ ์ด๋ค ํด๋์ค์์๋ ์์ ์ ์ธ์คํด์ค๋ฅผ ์ถ๊ฐ๋ก ๋ง๋ค์ง ๋ชปํ๋๋ก ํด์ผํ๋ค.
โ ๊ณ ์ ์ ์ธ ์ฑ๊ธํค ํจํด ๊ตฌํ
public class Singleton {
private static Singleton uniqueInstance;
// ์์ฑ์ : ์ธ๋ถ์์ ์์ฑํ์ง ๋ชปํ๋๋ก private
private Singleton(){}
// ์์ฑ์ ๋์ ์์ฑํ ๋ ์ฌ์ฉํ getInstance() ๋ฉ์๋
public static Singleton getInstance(){
if (uniqueInstance == null){
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
}
uniqueInstance๋ฅผ null ์ ์ฒดํฌํ์ฌ ์์ฑํ๋ฏ๋ก ์ ์ผํ ์ธ์คํด์ค๊ฐ ์ ์ฅ๋๋ค. ํ์ํ ์ํฉ์ด ๋๊ธฐ ์ ๊น์ง ์์ฑํ์ง ์์ผ๋ฏ๋ก ๊ฒ์ผ๋ฅธ ์ธ์คํด์ค ์์ฑ (lazy instantiation) ์ด๋ผ ํ๋ค.
์ด๋ ๊ฒ ์์ฑํ๊ณ ๊ทธ๋ฅ ๋ด์๋ ๋ณ๋ค๋ฅธ ๋ฌธ์ ๊ฐ ์์ด๋ณด์ธ๋ค. ๋ฌธ์ ๊ฐ ์์๊น?
๋ฉํฐ์ฐ๋ ๋ ์ผ ๋, 2๊ฐ์ ์ฐ๋ ๋์์ Singleton.getInstance() ๋ฉ์๋๋ฅผ ์คํ์ํจ๋ค๊ณ ๊ฐ์ ํด๋ณด์.
๋ฌธ์ ์ : ๋ฉํฐ ์ฐ๋ ๋ ํ๊ฒฝ์์ ์ทจ์ฝ
// 1๋ฒ ์ฐ๋ ๋
public static Singleton getInstance(){ // -> uniqueInstance : null ์ด๋ค
// 2๋ฒ ์ฐ๋ ๋๋ก ์ ์ด๊ถ ๋์ด๊ฐ
public static Singleton getInstance(){ // -> uniqueInstance : null ์ด๋ค
// 1๋ฒ ์ฐ๋ ๋๋ก ์ ์ด๊ถ ๋์ด๊ฐ
if (uniqueInstance == null) { // ์กฐ๊ฑด ๋ง์กฑ
// 2๋ฒ ์ฐ๋ ๋๋ก ์ ์ด๊ถ ๋์ด๊ฐ
if (uniqueInstance == null) { // ์กฐ๊ฑด ๋ง์กฑ
// 1๋ฒ ์ฐ๋ ๋๋ก ์ ์ด๊ถ ๋์ด๊ฐ
uniqueInstance = new Singleton(); // uniqueInstance : Object1 ์ธ์คํด์ค ์์ฑ
return uniqueInstance // Object1 ์ธ์คํด์ค ๋ฆฌํด
// 2๋ฒ ์ฐ๋ ๋๋ก ์ ์ด๊ถ ๋์ด๊ฐ
uniqueInstance = new Singleton(); // uniqueInstance : Object2 ์ธ์คํด์ค ์์ฑ
return uniqueInstance // Object2 ์ธ์คํด์ค ๋ฆฌํดโ
๊ฒฐ๊ณผ์ ์ผ๋ก ์ด๋ฐ ๋์์ผ๋ก ์ธํด ์๋ก ๋ค๋ฅธ ๋ ๊ฐ์ ๊ฐ์ฒด (Object1, Object2) ๊ฐ ์์ฑ๋์ด ๋ฒ๋ฆฐ๋ค.
์ฆ, ์ฐ๋ ๋ ์ธ์ดํ (thread safety) ํ์ง ์๋ค.
ํด๊ฒฐ๋ฐฉ๋ฒ์ ์์๊น? ์ฐ๋ ๋ ์ธ์ดํ ํ๊ฒ ๊ตฌํํ๋ ๋ฐฉ๋ฒ์ ์์๊น?
โ ๋๊ธฐํ (synchronized) ํค์๋๋ก ํด๊ฒฐํ๋ ๋ฐฉ๋ฒ
getInstance()๋ฅผ ๋๊ธฐํ์์ผ, ๋ฉํฐ์ค๋ ๋ฉ ๋ฌธ์ ๋ฅผ ๊ฐ๋จํ ํด๊ฒฐํ ์ ์๋ค.
public class Singleton {
private static Singleton uniqueInstance;
private Singleton() {}
// ๋๊ธฐํ : synchronized ์ถ๊ฐ
public static synchronized Singleton getInstance() {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
}
๋ฌธ์ ๋ ํด๊ฒฐ๋๋ค. ๊ทธ๋ฌ๋ ๋๊ธฐํ๋ ์ค๋ฒํค๋๋ฅผ ์ฆ๊ฐ์ํจ๋ค.
๋๊ธฐํ๊ฐ ๊ผญ ํ์ํ ์์ ์ ๋ฉ์๋๊ฐ ์์๋๋ ๋ ๋ฟ์ด๋ค.
uniqueInstance ๋ณ์์ Singleton ์ธ์คํด์ค๋ฅผ ๋์ ํ๊ณ ๋๋ฉด ๊ตณ์ด ๋๊ธฐํ ์ํ๋ก ์ ์ง์ํฌ ํ์๊ฐ ์์ด์ง๋ค.
โ ๋ ํจ์จ์ ์ธ ๋ฐฉ๋ฒ์ ์์๊น?
1. getInstance()์ ์๋๊ฐ ๊ทธ๋ฆฌ ์ค์ํ์ง ์๋ค๋ฉด ๊ทธ๋ฅ ๋๋ค.
getInstance() ๋ฉ์๋๊ฐ ์ดํ๋ฆฌ์ผ์ด์ ์ ํฐ ๋ถ๋ด์ ์ฃผ์ง ์๋๋ค๋ฉด ๊ทธ๋ฅ ๋์. ๋๊ธฐํ์ํค๋ ๊ฒ์ด ๊ทธ๋ฆฌ ์ด๋ ต์ง ์๊ณ , ํจ์จ์ ์ผ๋ก ๊ด์ฐฎ์ ์ ์๋ค. ๋จ, ๋ฉ์๋๋ฅผ ๋๊ธฐํ ์ํค๋ฉด ์ฑ๋ฅ์ด 100๋ฐฐ ์ ๋ ์ ํ๋๋ค๋ ๊ฒ์ ๊ธฐ์ตํด ๋์. ๋ง์ฝ, getInstance()๊ฐ ์ดํ๋ฆฌ์ผ์ด์ ์ ๋ณ๋ชฉ์ผ๋ก ์์ฉ๋๋ฉด ๋ค๋ฅธ ๋ฐฉ๋ฒ์ ์๊ฐํด์ผ ํ๋ค.
2. ์ธ์คํด์ค๋ฅผ ํ์ํ ๋ ์์ฑํ์ง๋ง๊ณ ์ฒ์๋ถํฐ ๋ง๋ค์ด ๋ฒ๋ฆฌ์. (์ด๋ฅธ ์ด๊ธฐํ : eager initialization)
public class Singleton {
// ์ด๋ฅธ ์ด๊ธฐํ : ์ธ์คํด์ค๋ฅผ ์ฒ์์ ์์ฑ
private static Singleton uniqueInstance = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return uniqueInstance;
}
}
์ดํ๋ฆฌ์ผ์ด์ ์ ๋ฐ๋์ Singleton์ ์ธ์คํด์ค๋ฅผ ์์ฑํ๊ณ , ํญ์ ์ฌ์ฉํ๋ค๋ฉด ๋๋ ์คํ์ค์ ์์๋ก ๋ง๋ค๊ณ ๊ด๋ฆฌํ๊ธฐ๊ฐ ๋ฒ๊ฑฐ๋กญ๋ค๋ฉด ์ฒ์๋ถํฐ Singleton ์ธ์คํด์ค๋ฅผ ๋ง๋ค์ด๋ฒ๋ฆฌ์. ์ด๋ ํด๋์ค๊ฐ ๋ก๋ฉ๋ ๋ JVM์์ Singleton์ ์ ์ผํ ์ธ์คํด์ค๋ฅผ ์์ฑํด์ค๋ค.
getInstance() ์์ ์์ฑ๋์ด ์๋ ํ๋์ ์ธ์คํด์ค๋ฅผ ๋ฐ๋ก ๋ฆฌํดํด์ฃผ๋ฏ๋ก ์ฐ๋ ๋ ์ธ์ดํ ํ๋ค.
๋จ์ ์ ๋ฏธ๋ฆฌ ๋ง๋ ๋ค๋๊ฒ ๊ทธ ์์ฒด๊ฐ ๋ ์ ์๋ค.
๋ฆฌ์์ค๋ฅผ์จ์ ์ธ์คํด์ค๋ฅผ ๋ฏธ๋ฆฌ ์์ฑํด๋์๋๋ฐ, ์ฌ์ฉํ์ง์๋๋ค๋ฉด ์์๋ญ๋น๊ฐ ๋๋ค.
๊ทธ๋์ ์ฐ๋ ๋ ์ธ์ดํ ํ๋ฉด์ ์ฌ์ฉ์ด ๋ ๋ ๋ง๋ค๊ณ ์ถ์ด์ง๋ค. (Thread Safety, Lazy Initialization)
๊ทธ๋ฌ์๋ synchronized ๋ฅผ ์ฌ์ฉํด์ผํ๋ ๋น์ฉ์ด ์ ๊ฒฝ์ฐ์ธ๋ค.
3. DCL (Double-Checking Locking) ์ ์จ์ getInstance() ์์ ๋๊ธฐํ๋๋ ๋ถ๋ถ์ ์ค์ด์.
public class Singleton {
// volatile์ ์ฌ์ฉ
private volatile static Singleton uniqueInstance;
private Singleton() {}
public static Singleton getInstance() {
if (uniqueInstance == null) {
synchronized (Singleton.class) {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
}
}
return uniqueInstance;
}
}
์๋ ๋ฐฉ๋ฒ๋ณด๋ค ์ ํจ์จ์ ์ผ๊น?
public static synchronized Singleton getInstance() {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
getInstance() ๋ฅผ ํธ์ถํ ๋๋ง๋ค ๋๊ธฐํ ๋งค์ปค๋์ฆ์ ์ฌ์ฉํ์ง ์๋๋ค. ๋จผ์ ์ธ์คํด์ค๊ฐ ์์ฑ๋์ด์๋์ง ํ์ธ ํ, ์์ฑ๋์ง ์์์๋๋ง synchronized ๋ฅผ ํ ์ ์๋ค. ๋ฉํฐ์ฐ๋ ๋๊ฐ ๋น๋ฒํ ๊ฒฝ์ฐ๋ฅผ ๋๋นํด์ ๋๋ธ ์ฒดํฌ ํ๋ ๋ฐฉ์์ผ๋ก synchronized ๋ฅผ ์ฌ์ฉํ๋ฏ๋ก ์ฑ๋ฅ์ ์ผ๋ก ๋น์ฐํ ๋ ์ฐ์ํ๋ค.
๋ฌธ์ ๋ volatile ํค์๋๋ฅผ ์ฌ์ฉํ๋ค๋ ๊ฒ์ด ๋ ์ ์๋ค.
volatile ํค์๋๋ฅผ ์ฌ์ฉํ๋ฉด ์๋ฐ์ ์ผ์ข ์ ์ต์ ํ์ธ ๋ฆฌ์ค๋๋ง์ ํํผํ์ฌ ์ฝ๊ธฐ์ ์ฐ๊ธฐ ์์๋ฅผ ๋ณด์ฅ, ๋ฉํฐ์ค๋ ๋ฉ์ ์ฐ๋๋ผ๋ uniqueInstance๋ณ์๊ฐ Singleton์ธ์คํด์ค๋ก ์ด๊ธฐํ ๋๋ ๊ณผ์ ์ด ์ฌ๋ฐ๋ฅด๊ฒ ์งํ๋๋๋ก ํ ์ ์๋ค. (DCL์ 1.5์ด์ ๋ฒ์ ์์๋ง ๊ฐ๋ฅ)
(์ฐธ๊ณ ) ๋ฆฌ์ค๋๋ง : ๋ณดํต ์ปดํ์ผ ๊ณผ์ ์์ ์ผ์ด๋๋ฉฐ, ํ๋ก๊ทธ๋๋จธ๊ฐ ๋ง๋ค์ด๋ธ ์ฝ๋๋ ์ปดํ์ผ ๋ ๋ ์ข๋ ๋น ๋ฅด๊ฒ ์คํ๋ ์ ์๋๋ก ์กฐ์์ด ๊ฐํด์ ธ ์ต์ ํ ๋จ
→ ๋ชจ๋ JVM๊ตฌํ์์ ์๋ํ๋๊ฒ์ ๋ณด์ฅํ ์๋ ์๊ธฐ ๋๋ฌธ์ DCL์ ์ฌ์ฉํ์ง ์๋๊ฒ ์ข๋ค.
4. static inner ํด๋์ค๋ฅผ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ
public class Singleton {
private Singleton() {}
// static inner ํด๋์ค ์ฌ์ฉ
private static class SingletonHolder {
private static final Singleton UNIQUE_INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.UNIQUE_INSTANCE;
}
}
๋ฉํฐ์ฐ๋ ๋ ํ๊ฒฝ์์ ์์ ํ๋ฉฐ, getInstance() ๊ฐ ํธ์ถ๋ ๋ ์์ฑ๋๋ฏ๋ก Lazy Initialization ์ด๋ค.
UML Class Diagram