¿Cómo crear un singleton, conoces varias formas?

“¿Cómo crear un singleton, sabes cuántas formas?” El entrevistador esbozó
una sonrisa fantasmal ... ¡ Afortunadamente, me acordé del “Libro” que había leído!


Con respecto a la creación de un singleton en el código, el Sr. Zihan resumió 6 formas comunes.
Inserte la descripción de la imagen aquí

Chino hambriento

Cree objetos directamente, no hay problemas de seguridad de subprocesos.
Elementos clave:

  • Una clase solo puede tener una instancia: el constructor está privatizado;
  • Debe crear esta instancia usted mismo: variables estáticas de la clase;
  • Debe proporcionar esta instancia a todo el sistema usted mismo: (1) exposición directa, (2) método de obtención de variables estáticas;

Cree una instancia del estilo chino hambriento directamente (conciso e intuitivo)

public class Singleton1 {
    
    
	// 使用public直接暴露
    public static final Singleton1 INSTANCE = new Singleton1();
    private Singleton1() {
    
    
    }
    // 使用public方法直接暴露
    public static Singleton1 getInstance(){
    
    
        return INSTANCE;
    }
}

Enumerado (más conciso)

/**
 * 推荐
 */
public enum SingletonEnum {
    
    
    INSTANCE
}

Bloque de código estático estilo chino hambriento (adecuado para instancias complejas)

/**
 * 基于外部配置的单例
 */
public class SingletonStaticBlock {
    
    
    public static final SingletonStaticBlock INSTANCE;
    private String info;
    static {
    
    
        Properties por = new Properties();
        try {
    
    
            por.load(SingletonStaticBlock.class.getClassLoader().getResourceAsStream("single.properties"));
        } catch (IOException e) {
    
    
            e.printStackTrace();
        }
        INSTANCE = new SingletonStaticBlock(por.getProperty("hello"));
    }

    private SingletonStaticBlock(String info) {
    
    
        this.info = info;
    }

    public String getInfo() {
    
    
        return info;
    }

    public void setInfo(String info) {
    
    
        this.info = info;
    }
}

Agregue archivos bajo recurso single.properties:

hello = Mr.zihan

A continuación lo probamos ~

    @Test
    public void testSingleton(){
    
    
//        Singleton singleton = new Singleton();//无法new
//        Singleton1 singleton1 = new Singleton1();//无法new
        System.out.println(SingletonEnum.INSTANCE);
        System.out.println(Singleton1.INSTANCE);
        System.out.println(SingletonStaticBlock.INSTANCE.getInfo());
    }

Resultados de la prueba:

INSTANCE
com.dwlijx.pattern.creation.single.Singleton1@eec5a4a
Mr.zihan

Hombre flojo

Retrasa la creación de objetos.
Puntos clave:

  • (1) Privatización de constructora
  • (2) La variable estática guarda la única instancia;
  • (3) Proporcionar un método estático para obtener el objeto de esta instancia.

El hilo no es seguro (apto para un solo hilo)

public class SingletonLazy {
    
    
	// 需要时再实例化
    private static SingletonLazy INSTANCE;
    private SingletonLazy() {
    
    
    }

    public static SingletonLazy getINSTANCE(){
    
    
        if (null == INSTANCE){
    
    
            INSTANCE = new SingletonLazy();
        }
        return INSTANCE;
    }
}

Desventajas: el hilo no es seguro, adecuado para escenarios de un solo hilo.
Pruébelo: es
posible que necesite algunos intentos más.

/**
     * 懒汉模式
     * 用两个线程getInstance,比对一下实例的hashCode
     */
    @Test
    public void securityTest() throws ExecutionException, InterruptedException {
    
    
        Callable<SingletonLazy> callableTask = new Callable<SingletonLazy>() {
    
    
            @Override
            public SingletonLazy call() throws Exception {
    
    
                return SingletonLazy.getINSTANCE();
            }
        };
        ExecutorService es = Executors.newFixedThreadPool(2);
        Future<SingletonLazy> f1 = es.submit(callableTask);
        Future<SingletonLazy> f2 = es.submit(callableTask);

        System.out.println(f1.get().hashCode());
        System.out.println(f2.get().hashCode());
        es.shutdown();
    }
1316864772
1685232414

Bloqueos de clase para garantizar la seguridad de los subprocesos (aplicable a subprocesos múltiples)

Sobre la base del ejemplo anterior, se agrega un medio para controlar la seguridad de subprocesos múltiples.

public class SingletonLazySafe {
    
    
    private static SingletonLazySafe instance;
	//构造方法私有
    private SingletonLazySafe() {
    
    
    }

    public static SingletonLazySafe getInstance(){
    
    
        // 双重校验锁提升效率
        if (null == instance){
    
    
            synchronized (SingletonLazySafe.class){
    
    
                if (null == instance){
    
    
                    instance = new SingletonLazySafe();
                }
            }
        }
        return instance;
    }
}

tener una prueba

1316864772
1316864772

Entonces, la pregunta es, ¿sabe por qué hashCode tiene el mismo valor cada vez que se inicializa? Por ejemplo 1316864772?

Forma de clase interna estática (adecuada para subprocesos múltiples)

(1) Privatización del constructor
(2) La variable estática de la clase interna guarda la única instancia; se
utiliza 内部类的加载特性: la clase interna no se inicializa automáticamente con la carga e inicialización de la clase externa, sino que se carga e inicializa por separado.

public class InnerClassLazySingleton {
    
    

    private InnerClassLazySingleton() {
    
    
    }

    public static class Inner{
    
    
        private static InnerClassLazySingleton INSTANCE = new InnerClassLazySingleton();
    }

    public static InnerClassLazySingleton getInstance(){
    
    
        return Inner.INSTANCE;
    }
}

tener una prueba

/**
     * 懒汉模式-解决线程安全问题
     * 用两个线程getInstance,比对一下实例的hashCode
     */
    @Test
    public void innerClassSingletonSafeTest() throws ExecutionException, InterruptedException {
    
    
        Callable<InnerClassLazySingleton> callableTask = new Callable<InnerClassLazySingleton>() {
    
    
            @Override
            public InnerClassLazySingleton call() throws Exception {
    
    
                return InnerClassLazySingleton.getInstance();
            }
        };
        ExecutorService es = Executors.newFixedThreadPool(2);
        Future<InnerClassLazySingleton> f1 = es.submit(callableTask);
        Future<InnerClassLazySingleton> f2 = es.submit(callableTask);

        System.out.println(f1.get().hashCode());
        System.out.println(f2.get().hashCode());
        es.shutdown();
    }

Resultados de la prueba:

1285044316
1285044316

Inserte la descripción de la imagen aquí

Gracias por tu apreciación. Oficial invitado, por favor deje un mensaje antes de irse ~ O deje sus preguntas y las discutiremos juntos ~

Inserte la descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/l714417743/article/details/108697935
Recomendado
Clasificación