Modo singleton (implementado en código Java)

Hay 23 tipos de patrones de diseño:

  • Modo de creación: modo singleton, modo de fábrica abstracto, modo de prototipo, modo de constructor, modo de fábrica.
  • Modo estructural: modo adaptador, modo puente, modo decoración, modo combinación, modo apariencia, modo peso mosca, modo agente.
  • Modo de comportamiento: modo de método de plantilla, modo de comando, modo de visitante, modo de iterador, modo de observador, modo de mediador, modo de nota, modo de intérprete (modo de intérprete), modo de estado, modo de estrategia, modo de cadena de responsabilidad (cadena de responsabilidad modo).

Después de eso, los explicaremos uno por uno en el orden anterior. Primero, veamos el modo singleton:

1. Introducción al patrón de diseño singleton

  • Asegúrese de que una clase tenga solo una instancia y proporcione un punto de acceso global a ella.
  • Es decir, se toma un cierto método para asegurar que en todo el sistema de software, solo puede haber una instancia de objeto para una determinada clase, y la clase solo proporciona un método (método estático) para obtener su instancia de objeto.

Dos. Ocho métodos de realización del patrón de diseño singleton

Hay ocho formas en el modo singleton:

  • Estilo chino hambriento (atributo estático)
  • Chino hambriento (bloque de código estático)
  • Lazy (hilo inseguro)
  • Lazy (método síncrono seguro para subprocesos)
  • Lazy (bloques de código sincronizados y seguros para subprocesos)
  • Doble verificación
  • Clase interna estática
  • Enumeración
    A continuación explicamos en orden, primero miramos el estilo chino hambriento (constante estática):

1. Estilo chino hambriento (atributo estático)

Proceder de la siguiente:

  1. La constructora está privatizada (para evitar nuevas).
  2. Crea objetos dentro de la clase.
  3. Exponer un método público estático.

Demostración de código:

public class SingletonMode01 {
    
    

    //1.构造器私有化 (防止 new )
    private SingletonMode01(){
    
    

    }

    //2.类的内部创建对象(静态属性)
    private static SingletonMode01 instance = new SingletonMode01();

    //3.向外暴露一个静态的公共方法。getInstance
    public static SingletonMode01 getInstance(){
    
    
        return instance;
    }

}

Ventajas y desventajas:

  • Ventajas: este método de escritura es relativamente simple, es decir, la instanciación se completa cuando se carga la clase. Evite los problemas de sincronización de subprocesos.
  • Desventajas: La instanciación se completa cuando se carga la clase, lo que no logra el efecto de Carga diferida. Si esta instancia nunca se utiliza de principio a fin, provocará una pérdida de memoria.

Este modo singleton está disponible, lo que puede provocar una pérdida de memoria.

2. Estilo chino hambriento (bloque de código estático)

Proceder de la siguiente:

  • Igual que 1 es para ejecutarse en el bloque de código estático al asignar una constante estática

Demostración de código:

public class SingletonMode02 {
    
    
    //1.构造器私有化 (防止 new )
    private SingletonMode02(){
    
    

    }

    //2.类的内部创建对象(静态常量)
    private static SingletonMode02 instance;
    
    //在静态代码中对静态常量赋值
    static{
    
    
        instance = new SingletonMode02();
    }

    //3.向外暴露一个静态的公共方法。getInstance
    public static SingletonMode02 getInstance(){
    
    
        return instance;
    }
}

Pros y contras:

  • Este método es similar al método anterior, excepto que el proceso de instanciación de clase se coloca en un bloque de código estático.Cuando se carga la clase, el código en el bloque de código estático se ejecuta para inicializar la instancia de la clase. Las ventajas y desventajas son las mismas que las anteriores.

Este modo singleton está disponible, pero puede causar una pérdida de memoria.

3. Perezoso (hilo inseguro)

Demostración de código:

public class SingletonMode03 {
    
    
    
    private static SingletonMode03 instance; 
    
    private SingletonMode03(){
    
    
        
    }
    
    //当调用getInstance才创建单例对象,饿汉式
    public static SingletonMode03 getInstance(){
    
    
        if(instance == null){
    
    
             instance = new SingletonMode03();
        }
        return instance;
    }
}

Pros y contras:

  • Tiene el efecto de Carga diferida, pero solo se puede usar en un solo hilo.
  • Si en el subproceso múltiple, un subproceso entra en el bloque de sentencia de juicio if (instancia == nulo), y no hay tiempo para ejecutarlo en el futuro, y otro subproceso también pasa la sentencia de juicio, entonces se generarán varias instancias. Por tanto, este método no se puede utilizar en un entorno multiproceso.

En el desarrollo real, no utilice este método.

4. Estilo de hombre perezoso (seguridad de subprocesos, método de sincronización)

Demostración de código:

public class SingletonMode04 {
    
    
    
    private static SingletonMode04 instance;
    
    private SingletonMode04(){
    
    
        
    }
    
    //加入了同步方法,解决线程不安全问题
    public static synchronized SingletonMode04 getInstance(){
    
    
        if(instance == null){
    
    
            instance = new SingletonMode04();
        }
        return instance;
    }
}

Pros y contras:

  • Resuelve el problema de la inseguridad del hilo
  • La eficiencia es demasiado baja Cuando cada hilo quiere obtener una instancia de la clase, la ejecución del método getInstance () debe sincronizarse. De hecho, este método es suficiente para ejecutar el código de instanciación solo una vez. Si desea obtener una instancia de esta clase más adelante, simplemente regrese directamente. El método es demasiado ineficaz para la sincronización.

En el desarrollo real, este método no se recomienda.

5. Lazy (bloques de código sincronizados y seguros para subprocesos)

public class SingletonMode05 {
    
    

    private static SingletonMode05 instance;

    private SingletonMode05 (){
    
    

    }

    //加入了同步代码块,解决线程不安全问题
    public static SingletonMode05 getInstance(){
    
    
        if(instance == null){
    
    
            synchronized (SingletonMode05.class){
    
    
                instance = new SingletonMode05();
            }
        }
        return instance;
    }
}

Ventajas y desventajas:

  • Este método estaba originalmente destinado a mejorar el cuarto método de implementación, porque el método de sincronización anterior era demasiado ineficiente, por lo que el bloque de código instanciado se generó de forma sincrónica.
  • Pero esta sincronización no juega un papel en la sincronización de subprocesos. De acuerdo con la situación encontrada en el tercer método de implementación, si un subproceso entra en el bloque de sentencia de juicio if (instancia == nula) y no hay tiempo para ejecutarlo en el futuro, otro subproceso también pasa la sentencia de juicio, entonces se generará Múltiples instancias

En el desarrollo real, este método no se puede utilizar

6. Verificación doble

public class SingletonMode06 {
    
    

    //volatile关键字:
    //1. 保证变量的可见性:当一个被volatile关键字修饰的变量被一个线程修改的时候,其他线程可以立刻得到修改之后的结果。
    //   当一个线程向被volatile关键字修饰的变量写入数据的时候,虚拟机会强制它被值刷新到主内存中。
    //   当一个线程用到被volatile关键字修饰的值的时候,虚拟机会强制要求它从主内存中读取。
    //2. 屏蔽指令重排序:指令重排序是编译器和处理器为了高效对程序进行优化的手段;
    //   它只能保证程序执行的结果时正确的,但是无法保证程序的操作顺序与代码顺序一致。
    //   这在单线程中不会构成问题,但是在多线程中就会出现问题。
    //   非常经典的例子是在单例方法中同时对字段加入voliate,就是为了防止指令重排序。
    private static volatile SingletonMode06 instance;

    private SingletonMode06() {
    
    

    }

    //使用双重检查
    public static SingletonMode06 getInstance() {
    
    
        if(instance == null){
    
    
            synchronized (SingletonMode06.class){
    
    
                if(instance == null){
    
    
                    instance = new SingletonMode06();
                }
            }
        }
        return instance;
    }
}

Ventajas y desventajas:

  • El concepto de Double-Check se usa a menudo en el desarrollo multiproceso.Como se muestra en el código, hemos realizado dos verificaciones if (instancia == null) para garantizar la seguridad de los subprocesos.
  • De esta manera, el código de instanciación solo necesita ejecutarse una vez, y cuando se accede de nuevo más tarde, juzgará si (instancia == null) y devolverá directamente el objeto instanciado, lo que también evita la sincronización repetida del método.
  • Este método es seguro para subprocesos; carga diferida; mayor eficiencia

En el desarrollo real, se recomienda utilizar este patrón de diseño singleton

7. Clase interna estática

public class SingletonMode07 {
    
    

    private SingletonMode07(){
    
    

    }

    private static class SingletonModeInstance{
    
    
        private static final SingletonMode07 INSTANCE = new SingletonMode07();
    }

    public static SingletonMode07  getInstance(){
    
    
        return SingletonModeInstance.INSTANCE;
    }
}

Ventajas y desventajas:

  • Este método utiliza un mecanismo de carga de clases para garantizar que solo haya un hilo al inicializar una instancia.
  • En el método de clase interna estática, INSTANCE no se instanciará inmediatamente cuando se cargue la clase SingletonMode07, pero cuando se necesite instanciación, se llamará al método getInstance para cargar la clase SingletonModeInstance, completando así la instanciación de SingletonMode07.
  • Las propiedades estáticas de la clase solo se inicializarán cuando la clase se cargue por primera vez, por lo que aquí JVM nos ayuda a garantizar la seguridad del hilo, cuando la clase se inicializa, otros hilos no pueden entrar.
  • Este método evita la inseguridad de los subprocesos, utiliza las características de las clases internas estáticas para implementar la carga diferida y es muy eficiente.

Se recomienda este método.

8. Enumeración

public enum SingletonMode08 {
    
    
    
    INSTANCE("单例模式",123456);

    private String name;
    private int number;

    SingletonMode08(String name, int number) {
    
    
        this.name = name;
        this.number = number;
    }

    @Override
    public String toString() {
    
    
        return "SingletonMode08{" +
                "name='" + name + '\'' +
                ", number=" + number +
                '}';
    }
}

Pros y contras:

  • Esto usa la enumeración agregada en JDK1.5 para implementar el modo singleton. No solo puede evitar problemas de sincronización de subprocesos múltiples, sino que también evita que la deserialización vuelva a crear nuevos objetos.
  • Este método es defendido por el autor de Effective Java, Josh Bloch.

De esta manera se recomienda

3. Resumen del patrón de diseño singleton

  • El modo singleton garantiza que solo haya un objeto de esta clase en la memoria del sistema, lo que ahorra recursos del sistema. Para algunos objetos que deben crearse y destruirse con frecuencia, el modo singleton puede mejorar el rendimiento del sistema.
  • Cuando desee crear una instancia de una clase singleton, debe recordar usar el método correspondiente para obtener el objeto en lugar de usar new
  • Escenarios utilizados en el modo singleton: objetos que deben crearse y destruirse con frecuencia, se consumen demasiado tiempo o recursos al crear objetos (es decir, objetos pesados), pero objetos de uso frecuente, objetos de herramientas, frecuentes Objetos que acceden a bases de datos o archivos (como fuentes de datos, fábricas de sesiones, etc.)

Supongo que te gusta

Origin blog.csdn.net/MrYushiwen/article/details/112316230
Recomendado
Clasificación