1. 싱글톤 모드의 특징
생성자 민영화
인스턴스화된 변수 참조는 개인화됩니다.
인스턴스를 얻는 방법은 공유됩니다.
2. 싱글톤 모드 애플리케이션 시나리오
전체 프로그램 실행에는 클래스의 인스턴스 하나만 허용됩니다.
인스턴스화한 다음 자주 제거해야 하는 개체입니다.
만드는 데 너무 많은 시간이나 리소스가 필요하지만 자주 사용되는 개체입니다.
서로 자원 소통이 가능한 환경
3. Java에서 싱글톤 모드를 작성하는 N가지 방법
이것이 가장 쉬운 방법이지만 단점은 클래스가 로드될 때 개체가 인스턴스화된다는 것입니다.
1) 배고픈 중국식
/**
* 饿汉式
*/
public class EaterSingleton {
private static final EaterSingleton INSTANCE = new EaterSingleton();
private EaterSingleton() {
}
public static EaterSingleton getInstance() {
return INSTANCE;
}
}
2) Lazy 모드 - 이중 검증
스레드 안전, 게으른 초기화. 이 방식은 다중 스레드 상황에서 안전하고 높은 성능을 유지할 수 있는 이중 잠금 메커니즘을 사용합니다.
/**
* 懒汉双重验证
*/
public class DoubleCheckSingleton {
private volatile static DoubleCheckSingleton INSTANCE = null;
private DoubleCheckSingleton() {
}
public static DoubleCheckSingleton getInstance() {
if (INSTANCE == null) {
synchronized (DoubleCheckSingleton.class) {
if (INSTANCE == null) {
INSTANCE = new DoubleCheckSingleton();
}
}
}
return INSTANCE;
}
}
3) 정적 내부 클래스 - 싱글톤 모드
JVM은 단일 케이스를 보장하며 외부 클래스가 로드될 때 내부 클래스는 로드되지 않으므로 지연 로드가 가능합니다.
package com.bytearch.designPattern.singleton;
/**
* 内部类
* 加载外部类时不会加载内部类
*/
public class AnonymousInnerClsSingleton {
private AnonymousInnerClsSingleton() {
}
private static class LazyHolder {
private final static AnonymousInnerClsSingleton INSTANCE = new AnonymousInnerClsSingleton();
}
public static AnonymousInnerClsSingleton getInstance() {
return LazyHolder.INSTANCE;
}
}
4) 싱글톤 모드 열거
스레드 동기화를 해결할 수 있을 뿐만 아니라 역직렬화도 방지할 수 있습니다. 열거형 싱글톤 패턴은 "Effective Java"에서 권장됩니다.
package com.bytearch.designPattern.singleton;
/**
* 内部枚举类单例模式
*/
public class Singleton {
private Singleton() {
}
/**
* 静态枚举
*/
enum SingletonEnum {
INSTANCE;
private Singleton singleton;
SingletonEnum() {
singleton = new Singleton();
}
private Singleton getInstance() {
return singleton;
}
}
public static Singleton getInstance() {
return SingletonEnum.INSTANCE.getInstance();
}
/**
* 测试
* @param args
*/
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(()-> {
System.out.println(Singleton.getInstance().hashCode());
}).start();
}
}
}
5. 컨테이너 싱글톤 패턴
/**
* 容器式单例模式
*/
public class ContainerSingleton {
private ContainerSingleton() {
}
private static Map<String, Object> singletonObjects = new ConcurrentHashMap<>();
public static Object getBean(String className) {
Object singletonObject = singletonObjects.get(className);
if (singletonObject == null) {
synchronized (singletonObjects) {
singletonObject = singletonObjects.get(className);
if (singletonObject == null) {
try {
try {
singletonObject = Class.forName(className).newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
singletonObjects.put(className, singletonObject);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
}
return singletonObject;
}
}
컨테이너 스타일 싱글톤 패턴은 스프링 프레임워크에서 사용됩니다.
스프링 소스 org/springframework/beans/factory/support/DefaultSingletonBeanRegistry.java를 살펴보겠습니다.
/**
* Return the (raw) singleton object registered under the given name.
* <p>Checks already instantiated singletons and also allows for an early
* reference to a currently created singleton (resolving a circular reference).
* @param beanName the name of the bean to look for
* @param allowEarlyReference whether early references should be created or not
* @return the registered singleton object, or {@code null} if none found
*/
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
4. 요약
싱글톤 모드에는 많은 "변종"이 있습니다. 위의 내용은 더 나은 구현 중 일부를 요약한 것입니다(모두 스레드로부터 안전함). 친구가 있다면 친구가 너무 많을 때 어떤 것을 사용해야 하는지 궁금할 수 있습니다. ?실제로 다 사용이 가능합니다 취미에 따라 1번 유형의 "배고픈 중국식"이 업무상 더 자주 쓰일 수 있습니다 개인적으로 "정적 이너 클래스-싱글톤 모드"를 추천합니다,
위의 모든 사람들은 "컨테이너 스타일 싱글톤 모드"도 "게으른 사람 모드-이중 검증"의 변형임을 쉽게 알 수 있습니다.
예를 들어 경량 소켓 연결 풀 구현 에서 "컨테이너 싱글톤 패턴"도 사용합니다 .
public class ConnectionPool {
/**
* key is ip:port, value is ConnectionManager
*/
private final static ConcurrentHashMap<String, ConnectionManager> CP = new ConcurrentHashMap<String, ConnectionManager>();
public static Connection getConnection(InetSocketAddress socketAddress) throws MyException {
if (socketAddress == null) {
return null;
}
String key = getKey(socketAddress);
ConnectionManager connectionManager;
connectionManager = CP.get(key);
if (connectionManager == null) {
synchronized (ConnectionPool.class) {
connectionManager = CP.get(key);
if (connectionManager == null) {
connectionManager = new ConnectionManager(socketAddress);
CP.put(key, connectionManager);
}
}
}
return connectionManager.getConnection();
}
}
5. 지원
이 콘텐츠가 당신에게 매우 고무적이라고 생각한다면 두 가지 작은 부탁을 드리고 싶습니다.
더 많은 사람들이 이 콘텐츠를 볼 수 있도록 [찾아보기/전달하기] 클릭 (좋든 싫든 보기/전달 다 훌리거니즘????)
공식 계정 [구조에 대해 이야기하기] 에 주의를 기울이십시오. 공식 계정의 배경은 다음 "숫자" 또는 "키워드"를 회신하고 귀하에게 적합한 전체 학습 자료 세트를 보내드립니다.
101: 자바 초급
102: 고급 자바 고급
103: 자바 인터뷰
![](https://img-blog.csdnimg.cn/img_convert/f197d15b4ee936efad45d7f37d32a8f7.png)