BackEnd/Java

싱글톀 νŒ¨ν„΄μ— λŒ€ν•΄μ„œ (Keyword : 싱글톀 λ””μžμΈ νŒ¨ν„΄)

ejyoovV 2021. 3. 15. 19:11

πŸ’‘ λ“€μ–΄κ°€κΈ° 전에

λ¬΄ν•œμœΌλ‘œ μ‘΄μž¬ν•˜λŠ” μžμ›μ€ μ‘΄μž¬ν•˜μ§€ μ•ŠλŠ”λ‹€. 컴퓨터가 μ œκ³΅ν•˜λŠ” μžμ› λ§ˆμ°¬κ°€μ§€λ‘œ μ œν•œλ˜μ–΄ μžˆλ‹€.

μ΄λŸ¬ν•œ μƒν™©μ—μ„œ μΈμŠ€ν„΄μŠ€κ°€ λ‚¨μš©λ˜λŠ” 것은 λ°”λžŒμ§ν•˜μ§€ μ•Šκ³ 

ν•˜λ‚˜μ˜ μžμ›μœΌλ‘œ λͺ¨λ‘κ°€ κ³΅μœ ν•΄μ„œ μ‚¬μš©ν•΄μ•Όν•˜λŠ” 경우 싱글톀 νŒ¨ν„΄μ€ μœ μš©ν•œ 방법이 될 수 μžˆλ‹€.

 

πŸ’‘ 싱글톀 νŒ¨ν„΄(Singleton pattern)μ΄λž€?

μ†Œν”„νŠΈμ›¨μ–΄ λ””μžμΈ νŒ¨ν„΄μ—μ„œ 싱글톀 νŒ¨ν„΄μ„ λ”°λ₯΄λŠ” ν΄λž˜μŠ€λŠ”, μƒμ„±μžκ°€ μ—¬λŸ¬ μ°¨λ‘€ ν˜ΈμΆœλ˜λ”λΌλ„, μ‹€μ œλ‘œ μƒμ„±λ˜λŠ” κ°μ²΄λŠ” ν•˜λ‚˜μ΄κ³  졜초 생성 이후에 호좜된 μƒμ„±μžλŠ” 졜초의 μƒμ„±μžκ°€ μƒμ„±ν•œ 객체λ₯Ό λ¦¬ν„΄ν•œλ‹€.

즉 μƒμ„±μžμ˜ 호좜이 반볡적으둜 이뀄져도 μ‹€μ œλ‘œ μƒμ„±λ˜λŠ” κ°μ²΄λŠ” 졜초 μƒμ„±λœ 객체λ₯Ό λ°˜ν™˜ ν•΄μ£ΌλŠ” 것이닀.

 

πŸ“ ν•˜λ‚˜μ˜ κ°μ²΄λ§Œμ„ 생성해 이후에 호좜된 κ³³μ—μ„œλŠ” μƒμ„±λœ 객체λ₯Ό λ°˜ν™˜ν•˜μ—¬ ν”„λ‘œκ·Έλž¨ μ „λ°˜μ—μ„œ ν•˜λ‚˜μ˜ μΈμŠ€ν„΄μŠ€λ§Œμ„ μ‚¬μš©ν•˜κ²Œ 함.

πŸ“ μ–΄λ–€ ν΄λž˜μŠ€κ°€ 졜초 ν•œλ²ˆλ§Œ λ©”λͺ¨λ¦¬λ₯Ό ν• λ‹Ήν•˜κ³ (Static) κ·Έ λ©”λͺ¨λ¦¬μ— 객체λ₯Ό λ§Œλ“€μ–΄ μ‚¬μš©ν•˜λŠ” λ””μžμΈ νŒ¨ν„΄μ„ μ˜λ―Έν•¨.

 

λ””μžμΈ νŒ¨ν„΄μ€ μ„ λ°° 개발자 뢄듀이 κ°œλ°œμ„ ν•˜μ‹œλ©΄μ„œ,

μ΄λŸ°μ‹μœΌλ‘œ κ°œλ°œμ„ ν•˜λ©΄ μ’‹λ‹€ 이런 것듀을 νŒ¨ν„΄μœΌλ‘œ μ •μ˜ν•œκ²ƒμ΄λ‹€.

λ”°λΌμ„œ 싱글톀 νŒ¨ν„΄λ„ λ””μžμΈ νŒ¨ν„΄ 쀑 ν•˜λ‚˜μ΄κ³ , κΌ­ μ¨μ•Όλ˜λŠ”κ²ƒμ€ μ•„λ‹ˆλ‹€. 상황에 맞게 μ“°λ©΄ λ˜λŠ” 것이닀.

 

 

 

πŸ’‘ 싱글톀 νŒ¨ν„΄ μ˜ˆμ‹œ

μ•„λž˜μ˜ μ˜ˆμ œλŠ” μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•œ BoardServiceImpl 클래슀둜

싱글톀 νŒ¨ν„΄ κ΅¬ν˜„ μ‹œ μΈν„°νŽ˜μ΄μŠ€μΈ IBoardServiceλ₯Ό νƒ€μž…μœΌλ‘œ μ§€μ •ν•œ λ’€,

BoardServiceImpl μƒμ„±μž 호좜 μ‹œ BoardDaoImpl객체λ₯Ό μƒμ„±ν•œλ‹€.(λ‹€ν˜•μ„± κ°œλ…)

public class BoardServiceImpl implements IBoardService{
	private IBoardDao boardDao;
	private Connection conn;
	
//	싱글톀 객체 μœ„ν•œ μžμ‹  객체 생성
	private static IBoardService boardService;
	
	private BoardServiceImpl() {
		boardDao = BoardDaoImpl.getInstance();
	}
	
	public static IBoardService getInstance() {
		if(boardService == null) {
			boardService = new BoardServiceImpl();
		}
		return boardService;
	}

클래슀 λ³€μˆ˜μ™€ μƒμ„±μžλ₯Ό μ™ΈλΆ€μ—μ„œ 생성할 수 없도둝 μ œν•œμ„ 두어

객체 생성 μ‹œ ν•˜λ‚˜μ˜ 객체의 μ£Όμ†Œλ§Œ μ‚¬μš©ν•˜λ„λ‘ ν•  수 μžˆλ‹€.

 

πŸ’‘ 싱글톀 νŒ¨ν„΄μ˜ μ‚¬μš©?

주둜 κ³΅ν†΅λœ 객체λ₯Ό μ—¬λŸ¬κ°œ μƒμ„±ν•΄μ„œ μ‚¬μš©ν•˜λŠ” DBCP(DataBase Connection Pool)κ³Ό 같은 μƒν™©μ—μ„œ 많이 μ‚¬μš©λœλ‹€.

 

πŸ’‘ 싱글톀 νŒ¨ν„΄μ„ μ‚¬μš©ν•˜λŠ” μ΄μœ λŠ”?

ν•œλ²ˆμ˜ 객체 μƒμ„±μœΌλ‘œ μž¬μ‚¬μš©μ΄ κ°€λŠ₯ν•˜κΈ° λ•Œλ¬Έμ— λ©”λͺ¨λ¦¬ λ‚­λΉ„λ₯Ό λ°©μ§€ν•  수 μžˆλ‹€.

μ‹±κΈ€ν†€μœΌλ‘œ μƒμ„±λœ κ°μ²΄λŠ” 무쑰건 ν•œλ²ˆ μƒμ„±μœΌλ‘œ 전역성을 띄기에 λ‹€λ₯Έ 객체와 κ³΅μœ κ°€ μš©μ΄ν•˜λ‹€.

 

πŸ’‘ 싱글톀 νŒ¨ν„΄μ˜ 문제점

싱글톀 νŒ¨ν„΄μ€ 전역성을 λ„λ©΄μ„œ

λ‹€λ₯Έ 객체와 κ³΅ν†΅μœΌλ‘œ μ‚¬μš©ν•˜λŠ” κ²½μš°μ™€ 같은 λͺ‡ κ°€μ§€ μΌ€μ΄μŠ€μ—μ„œλ§Œ μ‚¬μš©ν•  λ•Œ 효율적이며

κ·Έ μ™Έμ—λŠ” 문제점이 생길 수 μžˆλ‹€.

μ‹±κΈ€ν†€μœΌλ‘œ λ§Œλ“  객체의 역할이 κ°„λ‹¨ν•œ 것이 μ•„λ‹Œ 역할이 λ³΅μž‘ν•œ 경우라면

ν•΄λ‹Ή 싱글톀 객체λ₯Ό μ‚¬μš©ν•˜λŠ” λ‹€λ₯Έ κ°μ²΄κ°„μ˜ 결함도가 λ†’μ•„μ Έμ„œ

객체 μ§€ν–₯ 섀계 원칙에 μ–΄κΈ‹λ‚˜κ²Œ λœλ‹€. (개방-폐쇄)

ν•΄λ‹Ή 싱글톀 객체λ₯Ό μˆ˜μ •ν•  경우, 싱글톀 객체λ₯Ό μ‚¬μš©ν•˜λŠ” κ³³μ—μ„œ μ‚¬μ΄λ“œ 이팩트 λ°œμƒν•  ν™•λ₯ μ΄ μƒκΈ°κ²Œ 되며

λ©€ν‹° μ“°λ ˆλ“œ ν™˜κ²½μ—μ„œ 동기화 처리 문제 등이 μƒκΈ°κ²Œ λœλ‹€.

 


λ‹€μ–‘ν•œ μ‹±κΈ€ν†€μ˜ κ΅¬ν˜„

 

πŸ’‘ static block

public class ExampleClass1 {
	//Instance
	private static ExampleClass1 instance;
	
	//private construct
	private ExampleClass1() {}
	
	static {
		try {instance = new ExampleClass1();}
		catch(Exception e) { throw new RuntimeException(
				"Create instance fail. error mse = " + e.getMessage());}
	}
	
	public static ExampleClass1 getInstance() {
		return instance;
	}
}

μœ„μ™€ 같이 static λΈ”λŸ­μ„ μ‚¬μš©ν•  경우 ν΄λž˜μŠ€κ°€ λ‘œλ”©λ  λ•Œ ν•œλ²ˆλ§Œ 싀행을 ν•˜κ²Œλ˜λŠ” νŠΉμ„±μ„ μ‚¬μš©ν•œλ‹€.

ν•˜μ§€λ§Œ μΈμŠ€ν„΄μŠ€κ°€ μ‚¬μš©λ˜λŠ” μ‹œμ μ΄ μ•„λ‹Œ 클래슀 λ‘œλ”© μ‹œμ μ— μ‹€ν–‰λœλ‹€.

 

πŸ’‘ lazy init

μœ„ static λ°©λ²•μ—μ„œ κ°œμ„ ν•˜μ—¬ 클래슀 λ‘œλ”© μ‹œμ μ΄ μ•„λ‹Œ μΈμŠ€ν„΄μŠ€κ°€ ν•„μš”ν•˜μ—¬ μš”μ²­ν•  λ•Œ μƒμ„±λ˜λŠ” ν˜•νƒœλ‘œ μž‘μ„±ν•˜μ˜€λ‹€.

πŸ“ κΈ°λ³Έ μƒμ„±μžλ₯Ό private둜 μƒμ„±ν•˜μ—¬ μ™ΈλΆ€μ—μ„œ μΈμŠ€ν„΄μŠ€ 생성을 λΆˆκ°€λŠ₯ν•˜κ²Œ ν•˜κ³ , getInstanceλ₯Ό ν†΅ν•΄μ„œλ§Œ 생성이 κ°€λŠ₯ν•˜κ²Œ ν•œλ‹€.

πŸ“ getInstanceλŠ” λ‚΄λΆ€μ μœΌλ‘œ μƒμ„±λ˜μ§€ μ•Šμ•˜λ‹€λ©΄ 객체λ₯Ό μƒμ„±ν•˜κ³  기쑴에 μƒμ„±λœ 값이 μ‘΄μž¬ν•˜λ©΄ μƒμ„±λœ μΈμŠ€ν„΄μŠ€λ₯Ό λ¦¬ν„΄ν•˜λŠ” ν˜•νƒœλ‘œ ν”„λ‘œκ·Έλž¨ μ „λ°˜μ— 걸쳐 ν•˜λ‚˜μ˜ μΈμŠ€ν„΄μŠ€λ₯Ό μœ μ§€ν•œλ‹€.

πŸ“ μΈμŠ€ν„΄μŠ€λ₯Ό μ œκ³΅ν•˜λŠ” λ©”μ„œλ“œμ™€ μΈμŠ€ν„΄μŠ€ λ³€μˆ˜λŠ” λͺ¨λ‘ Static으둜 μ„ μ–Έλœ 정적 λ³€μˆ˜ 및 λ©”μ„œλ“œμ΄λ‹€.

πŸ“ κΈ°λ³Έ μƒμ„±μžλ₯Ό 톡해 생성할 수 μ—†κΈ° λ•Œλ¬Έμ— μ™ΈλΆ€μ—μ„œ μΈμŠ€ν„΄μŠ€μ— μ ‘κ·Όν•˜λ €λ©΄ λ‹Ήμ—°νžˆ 클래슀 λ³€μˆ˜ 및 λ©”μ„œλ“œμ— 접근을 ν—ˆμš©ν•΄μ•Όν•˜κΈ° λ•Œλ¬Έμ— 두 λ©”μ„œλ“œλŠ” 정적 νƒ€μž…μœΌλ‘œ μ„ μ–Έλœλ‹€.

public class ExampleClass2 {
	//Instance
	private static ExampleClass2 instance;
	
	//private construct
	private ExampleClass2() {}
	
	public static ExampleClass2 getInstance() {
		if(instance == null) {instance = new ExampleClass2();}
		return instance;
	}
}

πŸ“ ν•˜μ§€λ§Œ μœ„ ν˜•νƒœλ‘œ ꡬ성할 경우 λ©€ν‹° μ“°λ ˆλ“œ(Multi-Thread) ν™˜κ²½μ—μ„œ μ·¨μ•½ν•˜λ‹€.

μ—¬λŸ¬ μ“°λ ˆλ“œκ°€ 곡유되고 μžˆλŠ” μƒν™©μ—μ„œ 쑰건문이 λ™μ‹œμ— λ‘λ²ˆ 돌 수 있기 λ•Œλ¬Έμ— 

νŠΉμ • μ“°λ ˆλ“œκ°€ λ™μ‹œμ— getInstance() λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜κ²Œ 되면 μΈμŠ€ν„΄μŠ€κ°€ λ‘λ²ˆ μƒμ„±λ˜λŠ” λ¬Έμ œκ°€ λ°œμƒν•œλ‹€.

 

μ•„λž˜μ˜ μ½”λ“œμ—μ„œ count 값은 각기 λ‹€λ₯Έ μ“°λ ˆλ“œμ—μ„œ κ³΅μœ ν•˜κ³  있고 μ„œλ‘œ λ‹€λ₯Έ ν”„λ‘œμ„ΈμŠ€μ—μ„œ μ²˜λ¦¬ν•˜κ³  있기 λ•Œλ¬Έμ— 값이 μΌκ΄€λ˜μ§€ μ•Šμ„ 수 μžˆλ‹€.

public class ExampleClass5 {
	//Instance
	private static ExampleClass5 instance;
	private int count = 0;
	
	//private construct
	private ExampleClass5() {}
	
	public static ExampleClass5 getInstance() {
		if(instance == null) {instance = new ExampleClass5();}
		return instance;
	}
	
	public void print(String input) {
		count++;
		System.out.println(input + "count : " + count);
	}
}

 

 

πŸ’‘ Thread safe + lazy (정적 λ³€μˆ˜μ— μΈμŠ€ν„΄μŠ€λ₯Ό λ§Œλ“€μ–΄ λ°”λ‘œ μ΄ˆκΈ°ν™” ν•˜λŠ” 방법)

public class ExampleClass3 {
	//Instance
	private static ExampleClass3 instance;
	
	//private construct
	private ExampleClass3() {}
	
	public static synchronized ExampleClass3 getInstance() {
		if(instance == null) {instance = new ExampleClass3();}
		return instance;
	}
}

Lazyμ—μ„œ λ³΄μ˜€λ˜ getInstance() λ©”μ„œλ“œμ— synchronized ν‚€μ›Œλ“œλ₯Ό λΆ™μž„μœΌλ‘œμ¨ μ“°λ ˆλ“œμ—μ„œ λ™μ‹œ 접근에 λŒ€ν•œ 문제λ₯Ό ν•΄κ²°ν•˜μ˜€λ‹€.

ν•˜μ§€λ§Œ synchronized ν‚€μ›Œλ“œλŠ” μ„±λŠ₯ μ €ν•˜λ₯Ό λ°œμƒμ‹œν‚¨λ‹€.

 

πŸ’‘ Holder

public class ExampleClass4 {
	//private construct
	private ExampleClass4() {}
	
	private static class InnerInstanceClazz() {
		private static final ExampleClass4 instance = new ExampleClass4();
	}
	
	public static ExampleClass4 getInstance() {
		return InnerInstanceClazz.instance;
	}
}

JVM의 클래슀 λ‘œλ” λ©”μ»€λ‹ˆμ¦˜κ³Ό 클래슀의 λ‘œλ“œ μ‹œμ μ„ μ΄μš©ν•˜μ—¬ λ‚΄λΆ€ 클래슀λ₯Ό 톡해 생성 μ‹œν‚΄μœΌλ‘œμ¨ μ“°λ ˆλ“œ κ°„μ˜ 동기화 문제λ₯Ό ν•΄κ²°ν•œλ‹€.

μœ„ 방법은 ν˜„μž¬ Javaμ—μ„œ 싱글톀 μƒμ„±μ—μ„œ μ‚¬μš©ν•˜λŠ” λŒ€ν‘œμ μΈ 방법이닀.

ν˜„μž¬ λ‚΄κ°€ ν…ŒμŠ€νŠΈ ν• λ•Œμ—λŠ” μ € μ½”λ“œμ— 였λ₯˜κ°€ μžˆμ—ˆλ‹€.

ν˜„μž¬ μ§€μ‹μœΌλ‘œλŠ” 였λ₯˜λ₯Ό μž‘μ§€ λͺ»ν•œλ‹€. κ·Έλž˜μ„œ λ‚˜μ€‘μ— μ•Œκ²Œλ˜λ©΄ μ •λ¦¬ν•˜λ €κ³  ν•œλ‹€.

 

πŸ’‘ 정리

싱글톀 νŒ¨ν„΄μ€ Spring framework μ—μ„œλ„ 많이 μ‚¬μš©λ˜λ©°, μ–΄λ–€μ‹μœΌλ‘œ κ΅¬ν˜„ν•˜λŠ”μ§€ μ•Œμ•„λ‘λ©΄ 도움이 λœλ‹€.

μžλ°”μ™€ Spring μ—μ„œμ˜ 싱글톀 차이점이라면, 싱글톀 객체의 생λͺ…μ£ΌκΈ°κ°€ λ‹€λ₯΄λ‹€.

λ˜ν•œ μžλ°”μ—μ„œ κ³΅μœ λ²”μœ„λŠ” Class loader κΈ°μ€€μ΄μ§€λ§Œ, Springμ—μ„œλŠ” ApplicationContextκ°€ 기쀀이 λœλ‹€.

πŸ“ 싱글톀은 ν”„λ‘œκ·Έλž¨ μ „μ²΄μ—μ„œ ν•˜λ‚˜μ˜ κ°μ²΄λ§Œμ„ κ³΅ν†΅μœΌλ‘œ μ‚¬μš©ν•˜κ³  있기 λ•Œλ¬Έμ— 각 κ°μ²΄κ°„μ˜ 결합도가 λ†’μ•„μ Έμ„œ 변경에 μœ μ—°ν•˜κ²Œ λŒ€μ²˜ν•  수 μ—†λ‹€.

πŸ“ 싱글톀 객체가 λ³€κ²½λ˜λ©΄ 이λ₯Ό μ°Έμ‘°ν•˜κ³  μžˆλŠ” λͺ¨λ“  값듀이 λ³€κ²½λ˜μ–΄μ•Ό ν•˜λ―€λ‘œ, λ©€ν‹° μ“°λ ˆλ“œ ν™˜κ²½μ—μ„œ λŒ€μ²˜κ°€ μ–΄λŠμ •λ„ κ°€λŠ₯ν•˜μ§€λ§Œ, κ³ λ €ν•΄μ•Ό ν•  μš”μ†Œκ°€ λ§Žμ•„ μ‚¬μš©μ΄ μ–΄λ ΅κ³  ν”„λ‘œκ·Έλž¨ μ „λ°˜μ— κ±Έμ³μ„œ ν•„μš”ν•œ λΆ€λΆ„μ—λ§Œ μ‚¬μš©ν•œλ‹€λ©΄ μž₯점이 μžˆλ‹€. (포인트λ₯Ό 작기 μ–΄λ ΅κΈ΄ ν•˜λ‹€.)

πŸ“ μ μ ˆν•œ ν˜•νƒœλ‘œ 싱글톀을 ν™œμš©ν•˜λ©΄ μ’‹μ§€λ§Œ λ‚¨μš©ν•˜κ²Œ 될 μ—¬μ§€κ°€ λ§Žλ‹€.

πŸ“ λ©€ν‹° μ“°λ ˆλ“œ ν™˜κ²½μ—μ„œμ˜ 싱글톀 

- Synchronizedλ₯Ό 톡해 κ΄€λ¦¬ν•˜λ©΄ 되며, λ‹€μ–‘ν•œ 변화에 λŒ€μ‘ν•˜κΈ° μœ„ν•΄ μΈν„°νŽ˜μ΄μŠ€μ˜ ν˜•νƒœλ‘œ κ΄€λ¦¬ν•˜λ©΄ μ’‹λ‹€.

πŸ“ 단일 μ“°λ ˆλ“œ ν™˜κ²½μ—μ„œμ˜ 싱글톀

- 정적 클래슀의 ν˜•νƒœλ‘œ μ‚¬μš©ν•˜λ©΄ λœλ‹€. (클래슀 λ‘œλ”©λ‹¨κ³„μ—μ„œ λ°”λ‘œ μ΄ˆκΈ°ν™”λ˜λ„λ‘)

- ν…ŒμŠ€νŠΈλ₯Ό μœ„ν•œ λͺ¨μ˜ 객체λ₯Ό λ§Œλ“€κ³  ν˜Ήμ€ λ‹€λ₯Έ λͺ©μ μœΌλ‘œ μ‚¬μš©ν•œλ‹€λ©΄ λ©€ν‹° μ“°λ ˆλ“œ ν™˜κ²½μ—μ„œ 싱글톀을 μ‚¬μš©ν•˜λ“―μ΄ μ‚¬μš©ν•œλ‹€.

 

 

 

 

 

 

 

 

 

 

μ°Έκ³  λΈ”λ‘œκ·Έ