싱글톤 패턴
싱글턴 패턴은 Java에서 가장 간단한 디자인 패턴 중 하나입니다. 이러한 유형의 디자인 패턴은 객체를 생성하는 최적의 방법을 제공하는 생성 패턴입니다.
이 패턴에는 단일 객체만 생성되도록 하면서 자체 객체 생성을 담당하는 단일 클래스가 포함됩니다. 이 클래스는 클래스의 개체를 인스턴스화할 필요 없이 고유한 개체에 직접 액세스할 수 있는 방법을 제공합니다.
참고:
1. 싱글톤 클래스는 인스턴스를 하나만 가질 수 있습니다.
2. 싱글톤 클래스는 고유한 인스턴스를 생성해야 합니다.
3. 싱글톤 클래스는 이 인스턴스를 다른 모든 개체에 제공해야 합니다.
소개
의도: 클래스에 인스턴스가 하나만 있는지 확인하고 이에 대한 전역 액세스 지점을 제공합니다.
주요 해결 방법: 글로벌하게 사용되는 클래스는 자주 생성되고 소멸됩니다.
사용 시기: 인스턴스 수를 제어하고 시스템 리소스를 절약하고 싶을 때.
해결 방법: 시스템에 이미 이 싱글톤이 있는지 확인하고, 있으면 반환하고, 없으면 생성하세요.
키 코드: 생성자는 비공개입니다.
적용 예: 1. 파티에는 의장이 한 명만 있을 수 있습니다. 2. Windows는 다중 프로세스, 다중 스레드로 구성되어 있어 파일을 운영할 때 여러 프로세스나 스레드가 동시에 파일을 운영하는 것은 불가피합니다. 따라서 모든 파일 처리는 고유한 인스턴스를 통해 수행되어야 합니다. 3. 일부 장치 관리자는 싱글톤 모드로 설계되는 경우가 많습니다. 예를 들어 컴퓨터에 프린터가 두 대 있는 경우 출력 시 두 프린터가 동일한 파일을 인쇄할 수 없도록 처리해야 합니다.
장점: 1. 메모리에 인스턴스가 하나만 있으므로 특히 인스턴스가 자주 생성되고 삭제되는 경우(예: 경영대학원 홈페이지 페이지 캐시) 메모리 오버헤드가 줄어듭니다. 2. 자원의 다중 점유(예: 파일 쓰기 작업)를 피하십시오.
단점: 인터페이스가 없고 상속이 없으며 단일 책임 원칙과 충돌합니다. 클래스는 외부에서 인스턴스화하는 방법이 아니라 내부 논리에만 관심을 가져야 합니다.
사용 시나리오: 1. 고유 일련번호 생성을 요청합니다. 2. WEB의 카운터는 새로 고칠 때마다 데이터베이스에 추가할 필요가 없으며 단일 인스턴스로 먼저 캐시됩니다. 3. 생성된 객체는 I/O, 데이터베이스 연결 등의 리소스를 너무 많이 소비합니다.
참고: 동기화 잠금 동기화(Singleton.class)는 여러 스레드가 동시에 진입하여 인스턴스가 여러 번 인스턴스화되는 것을 방지하기 위해 getInstance() 메서드에서 사용해야 합니다.
Implementation
SingleObject 클래스를 생성하겠습니다. SingleObject 클래스에는 전용 생성자와 자체 정적 인스턴스가 있습니다.
SingleObject 클래스는 외부 세계에서 정적 인스턴스를 얻을 수 있는 정적 메서드를 제공합니다. SingletonPatternDemo, 우리의 데모 클래스는 SingleObject 클래스를 사용하여 SingleObject 개체를 가져옵니다.
1단계
싱글톤 클래스를 만듭니다.
SingleObject.java
public class SingleObject { //创建 SingleObject 的一个对象 private static SingleObject instance = new SingleObject(); //让构造函数为 private,这样该类就不会被实例化 private SingleObject(){} //获取唯一可用的对象 public static SingleObject getInstance(){ return instance; } public void showMessage(){ System.out.println("Hello World!"); } }
2단계
싱글톤 클래스에서 고유한 개체를 가져옵니다.
SingletonPatternDemo.java
public class SingletonPatternDemo { public static void main(String[] args) { //不合法的构造函数 //编译时错误:构造函数 SingleObject() 是不可见的 //SingleObject object = new SingleObject(); //获取唯一可用的对象 SingleObject object = SingleObject.getInstance(); //显示消息 object.showMessage(); } }
3단계
출력을 확인합니다.
Hello World!
싱글턴 패턴을 구현하는 여러 가지 방법
싱글턴 패턴을 구현하는 방법은 다음과 같이 다양합니다.
1. 게으른 스타일, 스레드가 안전하지 않음
지연 초기화:예
아니요 멀티 스레드 안전 : 아니요
구현 난이도: Easy
설명: 이 방법은 가장 기본적인 구현 방법입니다. 이 구현의 가장 큰 문제점은 멀티스레딩을 지원하지 않는다는 것입니다. 동기화된 잠금이 없기 때문에 엄격한 의미에서 싱글톤 모드로 간주되지 않습니다.
이 지연 로딩 방법은 스레드 안전성이 필요하지 않으며 다중 스레드에서 제대로 작동할 수 없습니다.
코드 예:
public class Singleton { private static Singleton instance; private Singleton (){} public static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }
다음에 소개하는 구현 방법은 모두 멀티스레딩을 지원하지만 성능에는 차이가 있습니다.
2. 게으른 스타일, 스레드 안전
지연 초기화 여부: 예
멀티 스레드 안전 여부: 예
구현 난이도: 쉬움
설명: 이 방법은 매우 좋습니다. 지연 로딩은 멀티 스레드에서 잘 작동할 수 있지만 매우 비효율적이며 99%의 경우 동기화가 필요하지 않습니다.
장점: 메모리 낭비를 피하기 위해 첫 번째 호출 후에만 초기화됩니다.
단점: 싱글톤을 보장하려면 동기화를 잠가야 하지만 잠금은 효율성에 영향을 미칩니다.
getInstance()의 성능은 애플리케이션에 그다지 중요하지 않습니다(이 메서드는 덜 자주 사용됩니다).
코드 예:
public class Singleton { private static Singleton instance; private Singleton (){} public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }
3, Hungry Chinese style
지연 초기화 여부: No
멀티 스레드 안전 여부: 예
구현 어려움: 쉽다
설명: 이 방법이 더 일반적으로 사용되지만 가비지 개체를 생성하기 쉽습니다.
장점: 잠금이 없으며 실행 효율성이 향상됩니다.
단점: 로드 시 클래스가 초기화되어 메모리가 낭비됩니다.
클래스로더 메커니즘을 기반으로 멀티스레드 동기화 문제를 방지합니다. 그러나 클래스가 로드될 때 인스턴스가 인스턴스화되지만, 대부분은 싱글톤 모드에서 getInstance 메소드를 호출하지만 그렇지 않습니다. 클래스 로딩을 발생시키는 다른 방법(또는 다른 정적 메소드)이 있어야 합니다. 이때 인스턴스를 초기화해도 지연 로딩 효과가 발생하지 않습니다.
코드 예:
public class Singleton { private static Singleton instance = new Singleton(); private Singleton (){} public static Singleton getInstance() { return instance; } }
4. 이중 확인 잠금/이중 확인 잠금(DCL, 이중 확인 잠금)
JDK 버전: JDK1.5 이상
지연 초기화 여부: 예
멀티 스레드 안전인가요? 예
구현 난이도: 더 복잡함
설명: 이 방법은 안전하고 멀티 스레드 상황에서 높은 성능을 유지할 수 있는 이중 잠금 메커니즘을 사용합니다.
getInstance()의 성능은 애플리케이션에 매우 중요합니다.
코드 예:
public class Singleton { private volatile static Singleton singleton; private Singleton (){} public static Singleton getSingleton() { if (singleton == null) { synchronized (Singleton.class) { if (singleton == null) { singleton = new Singleton(); } } } return singleton; } }
5. 등록된/정적 내부 클래스
지연 초기화 여부: 예
멀티 스레드 안전 여부: 예
구현 어려움: 일반
설명: 이 방법은 이중 확인 잠금 방법과 동일한 효과를 얻을 수 있지만 구현이 더 간단합니다. 정적 필드에 지연 초기화를 사용하십시오. 이 방법은 이중 확인 잠금 방법 대신 사용해야 합니다. 이 방법은 정적 도메인에만 적용 가능합니다. 인스턴스 도메인에 지연된 초기화가 필요한 경우 이중 확인 잠금 방법을 사용할 수 있습니다.
이 방법은 또한 클래스로더 메커니즘을 사용하여 인스턴스를 초기화할 때 스레드가 하나만 있는지 확인합니다. 이는 세 번째 방법과 다릅니다. 세 번째 방법에서는 싱글톤 클래스가 로드되는 한 인스턴스가 인스턴스화됩니다. 지연 로딩 효과에 도달하지 않음) 이러한 방식으로 Singleton 클래스가 로드되고 인스턴스가 반드시 초기화되지는 않습니다. SingletonHolder 클래스는 적극적으로 사용되지 않기 때문에 SingletonHolder 클래스는 인스턴스를 인스턴스화하기 위해 getInstance 메서드를 호출해야만 명시적으로 로드됩니다. 인스턴스를 인스턴스화하는 데 리소스가 소비되어 느리게 로드되기를 원한다고 상상해 보세요. 반면에 Singleton 클래스가 적극적으로 사용될 수 있다는 보장이 없기 때문에 Singleton 클래스가 로드될 때 인스턴스화하고 싶지 않을 것입니다. 다른 위치에서 로드 중이므로 현재 인스턴스를 인스턴스화하는 것은 분명히 부적절합니다. 현시점에서는 이 방법이 세 번째 방법보다 더 타당해 보인다.
코드 예:
public class Singleton { private static class SingletonHolder { private static final Singleton INSTANCE = new Singleton(); } private Singleton (){} public static final Singleton getInstance() { return SingletonHolder.INSTANCE; } }
6, 열거형
JDK 버전: JDK1.5 이상
지연 초기화 여부: 아니요
-스레드 안전: 예
구현 난이도: Easy
설명: 이 구현 방법은 널리 채택되지는 않았지만 싱글톤 패턴을 구현하는 가장 좋은 방법입니다. 더 간결하고 직렬화 메커니즘을 자동으로 지원하며 다중 인스턴스화를 절대적으로 방지합니다.
이 방법은 Effective Java 작성자인 Josh Bloch가 옹호합니다. 이 방법은 다중 스레드 동기화 문제를 방지할 뿐만 아니라 직렬화 메커니즘을 자동으로 지원하여 역직렬화가 새 객체를 다시 생성하는 것을 방지하고 다중 인스턴스화를 절대적으로 방지합니다. 하지만 Enum 기능은 JDK 1.5 이후에 추가된 기능이기 때문에 이렇게 작성하면 낯설게 느껴지고, 실제 업무에서는 거의 사용되지 않습니다.
전용 생성자는 반사 공격을 통해 호출할 수 없습니다.
코드 예:
public enum Singleton { INSTANCE; public void whateverMethod() { } }
경험: 일반적으로 1차, 2차 게으른 방법은 사용하지 않는 것이 좋으며, 3차 배고픈 방법을 사용하는 것이 좋습니다. 다섯 번째 등록 방법은 지연 로딩 효과가 명시적으로 구현된 경우에만 사용됩니다. 객체를 생성하기 위해 역직렬화가 필요한 경우 여섯 번째 열거 방법을 시도해 볼 수 있습니다. 다른 특별한 요구 사항이 있는 경우 네 번째 이중 확인 잠금 방법을 사용하는 것을 고려할 수 있습니다.