하나의 클래스에 오직 하나의 인스턴스만 가지는 패턴
싱글톤 패턴은 모듈 간의 결합을 강하게 만들 수 있다는 단점이 있다
👉 이때, 의존성 주입을 통해 모듈 간의 결합을 조금 더 느슨하게 만들어 해결할 수 있다
💡 A가 B에 의존성이 있다 👉 B의 변경 사항에 대해 A 또한 변해야 된다
💡 의존성 주입이란?
메인 모듈이 ‘직접’ 다른 하위 모듈에 의존성을 주지 않고, 의존성 주입자를 중간에 둬서 간접적으로 의존성을 주입하는 방식
싱글톤 클래스의 인스턴스를 클래스 로딩 단계에서 생성하는 방법
public class Singleton {
private static final Singleton instance = new Singleton();
// private constructor to avoid client applications to use constructor
private Singleton(){}
public static Singleton getInstance(){
return instance;
}
}
Eager Initialization과 유사하나, static block을 통해서 Exception Handling에 대한 옵션 제공
public class Singleton {
private static Singleton instance;
private Singleton(){}
//static block initialization for exception handling
static{
try{
instance = new Singleton();
}catch(Exception e){
throw new RuntimeException("Exception occured in creating singleton instance");
}
}
public static Singleton getInstance(){
return instance;
}
}
global access 한 getInstance() 메소드를 호출할 때에 인스턴스가 없다면 생성 👉 처음 사용할 때 초기화
public class Singleton {
private static Singleton instance;
private Singleton(){}
public static Singleton getInstance(){
if(instance == null){
instance = new Singleton();
}
return instance;
}
}
Lazy Initialization의 multi-thread 환경에서 동기화 문제를 해결하기 위한 방법 👉 getInstance() 메소드에 synchronized를 걸어두는 방식
💡 Synchronized
임계 영역 (Critical Section)을 형성해 해당 영역에 오직 하나의 thread만 접근 가능하게 해준다.
public class Singleton {
private static Singleton instance;
private Singleton(){}
public static synchronized Singleton getInstance(){
if(instance == null){
instance = new Singleton();
}
return instance;
}
}
// double checked locking
public static Singleton getInstance(){
if(instance == null){
synchronized (Singleton.class) {
if(instance == null){
instance = new Singleton();
}
}
}
return instance;
}
inner static helper class를 사용하는 방식
앞선 방식의 문제점들을 대부분 해결한 방식으로, 현재 가장 널리 쓰이는 싱글톤 구현 방법
public class Singleton {
private Singleton(){}
private static class SingletonHelper{
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance(){
return SingletonHelper.INSTANCE;
}
}
public class demo {
public static void main(String[] args) {
Singleton a = Singleton.getInstance();
Singleton b = Singleton.getInstance();
}
}
enum 타입을 사용
public enum EnumSingleton {
INSTANCE;
public static void doSomething(){
//do something
}
}
public class EnumDemo{
public static void main(String[] args) {
EnumSingleton singleton = EnumSingleton.INSTANCE;
...
}
}