삶 가운데 남긴 기록 AACII.TISTORY.COM
Singleton Pattern 과 DeadLock 본문
싱글톤 패턴: 하나의 인스턴스만 사용하기 위한 디자인 패턴, 스레드 풀링, 커넥션 풀링 등에서 주로 사용합니다.
- 인스턴스를 생성할 때 참조 변수를 private static으로 합니다.
- 생성자를 private로 한다. 이는 외부에서 new로 인스턴스를 생성하지 못하게 합니다.
- 인스턴스를 리턴하는 public static getInstance() 메서드를 제공합니다. 이 메서드 내부에서 인스턴스를 생성할 때 null 체크 후 생성해서 인스턴스를 리턴 해야 합니다.
- 멀티스레드 환경에서는 위 getInstance메서드를 synchronized 해야 안전합니다. 하지만 전반적인 성능 저하 때문에 일반적으로 아래와 같은 패턴으로 코딩합니다.
싱글톤패턴1
public class InitializationOnDemandHolderIdiom {
private InitializationOnDemandHolderIdiom () {}
private static class Singleton {
private static final InitializationOnDemandHolderIdiom instance = new InitializationOnDemandHolderIdiom();
}
public static InitializationOnDemandHolderIdiom getInstance () {
System.out.println("create instance");
return Singleton.instance;
}
}
싱글톤패턴2
public enum EnumInitialization {
INSTANCE;
static String test = "";
public static EnumInitialization getInstance() {
test = "test";
return INSTANCE;
}
}
이처럼 enum 열거형을 반환값으로 가지면서 대문자로 INSTANCE;를 선헌해주면 JVM에서 싱글톤 인스턴스를 보장해줍니다.
- 스레드 안전성(Thread-Safety): 여러 스레드에서 동시에 접근해도 인스턴스가 여러 개 생성되지 않도록 보장합니다.
- 직렬화(Serialization) 보장: 직렬화/역직렬화 과정에서도 싱글톤이 깨지지 않습니다.
- 리플렉션(Reflection) 방어: 리플렉션을 통한 강제적인 인스턴스 생성을 막아줍니다.
enum을 sigleton으로 만들면 new로 객체를 생성할 필요 없이 INSTANCE 상수를 직접 사용하면 됩니다.
public class Main {
public static void main(String[] args) {
// 'new'로 생성하지 않고, INSTANCE를 직접 참조합니다.
MySingleton singletonA = MySingleton.INSTANCE;
singletonA.doSomething(); // "싱글톤 인스턴스가 동작합니다."
// 프로그램의 다른 어디에서 접근하더라도...
MySingleton singletonB = MySingleton.INSTANCE;
singletonB.anotherMethod(); // "항상 동일한 인스턴스가 이 메서드를 실행합니다."
// 두 참조는 항상 동일한 객체를 가리킵니다.
if (singletonA == singletonB) {
System.out.println("A와 B는 정확히 같은 인스턴스입니다.");
}
}
}
멀티스레드 Deadlock 방지를 위한 고려 사항들
- 멀티스레드에서 내부에서 호출하는 메서드 중에서 인스턴스의 멤버 변수에 접근할 때는 synchronized 해주어야한다.
- 멀티스레드 환경에서는 singleton 패턴으로 인스턴스를 하나만 생성해서는 병목현상이 일어나므로 되도록 singleton 패턴을 안 쓰는 것이 좋다.
- 서블릿 프로그램에서 서블릿 클래스에 멤버 변수를 정의하지 말라. 서블릿 인스턴스는 컨테이너에서 싱글톤 처럼 동작(한 번 생성한 인스턴스를 재활용)하므로 스레드 경합시 데이터 값을 보장할 수 없기 때문이다.
- 오픈 호출: lock을 확보하지 않은 상태로 메서드 호출 하는 기법
- lock의 시간제한: 암묵적인 락 synchronized 말고 락 시간을 제한할 있는 Lock 클래스의 tryLock 메소드를 사용한다.
- 순환대기 (circular wait) 예방 : 프로그래밍에서 적용할 수 있는 현실적인 방법이다. 여러가지 아이디어가 있을 수 있지만 핵심은 lock을 걸어주는 타이밍을 잘 조정해 주어서 순환 대기가 발생하지 않게 하는 것이다.
- synchronized 동기화 블록 최소화
참고 URL
https://blog.seotory.com/post/2016/03/java-singleton-pattern

728x90
'DEV&OPS > Java' 카테고리의 다른 글
| Jenkins로 AWS에 배포 (0) | 2025.11.01 |
|---|---|
| Jenkins (젠킨스) (0) | 2025.11.01 |
| build.gradle 의 기본 (0) | 2025.10.30 |
| gradle and groovy (1) | 2025.10.30 |
| JAVA Thread (1) | 2025.03.27 |
