디자인 패턴 시리즈의 싱글톤 패턴을 말하다

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. 지원

이 콘텐츠가 당신에게 매우 고무적이라고 생각한다면 두 가지 작은 부탁을 드리고 싶습니다.

  1. 더 많은 사람들이 이 콘텐츠를 볼 수 있도록 [찾아보기/전달하기] 클릭 (좋든 싫든 보기/전달 다 훌리거니즘????)

  2. 공식 계정 [구조에 대해 이야기하기] 에 주의를 기울이십시오. 공식 계정의 배경은 다음 "숫자" 또는 "키워드"를 회신하고 귀하에게 적합한 전체 학습 자료 세트를 보내드립니다.

    101: 자바 초급

    102: 고급 자바 고급

    103: 자바 인터뷰

건축에 대해 이야기하기

추천

출처blog.csdn.net/weixin_38130500/article/details/106632441