Patrón de diseño: patrón singleton (que incluye: estilo de hombre hambriento, estilo de hombre perezoso, verificación doble, clase interna estática, enumeración)

 Enlaces relacionados:

[Patrón de diseño] Columna: [Patrón de diseño] Columna

Se pueden descargar códigos de muestra relevantes:  Ejemplos de patrones de diseño comunes en Java

patrón único

        Singleton Pattern (Patrón Singleton) es uno de los patrones de diseño más simples en Java. Este tipo de patrón de diseño es un patrón de creación, que proporciona una forma óptima de crear objetos.

        Este patrón implica una sola clase que es responsable de crear sus propios objetos mientras se asegura de que solo se cree un único objeto. Esta clase proporciona una forma de acceder a su único objeto, directamente, sin instanciar un objeto de esta clase.

El llamado singleton significa que todo el programa tiene una sola instancia . Esta clase es responsable de crear sus propios objetos mientras se asegura de que solo se cree un objeto. En Java, generalmente se usa en la implementación de clases de herramientas o la creación de objetos que consumen recursos.

        En el sistema informático, hay papeleras de reciclaje de Windows, sistemas de archivos en el sistema operativo, grupos de subprocesos en subprocesos múltiples, objetos de controlador para tarjetas gráficas, servicios de procesamiento en segundo plano para impresoras, objetos de registro para aplicaciones, grupos de conexiones para bases de datos y conexiones a sitios web. de , objetos de configuración de aplicaciones web, cuadros de diálogo en aplicaciones, cachés en el sistema, etc. a menudo se diseñan como singletons.

        El modelo singleton también se usa ampliamente en la vida real, por ejemplo, el director ejecutivo de la empresa, el gerente de departamento, etc., todos pertenecen al modelo singleton. ServletContext y ServletContextConfig en el estándar J2EE, ApplicationContext en la aplicación Spring Framework y el grupo de conexiones en la base de datos también son patrones singleton.

Características del patrón singleton

  • Una clase singleton solo puede tener una instancia.

  • Una clase singleton debe crear su propia instancia única.

  • Una clase singleton debe proporcionar esta instancia a todos los demás objetos .

Ventajas y desventajas del patrón singleton

ventaja:

  • El modo singleton puede garantizar que solo haya una instancia en la memoria, lo que reduce la sobrecarga de memoria

  • Se puede evitar la ocupación múltiple de recursos

  • El modo singleton establece un punto de acceso global, que puede optimizar y compartir el acceso a los recursos

defecto:

  • El modo singleton generalmente no tiene interfaz y es difícil de expandir . Si desea expandir, no hay una segunda forma excepto modificar el código original, lo que viola el principio de apertura y cierre.

  • En las pruebas concurrentes, el patrón singleton no conduce a la depuración de código. Durante el proceso de depuración, si no se ejecuta el código del singleton, no se puede simular un nuevo objeto.

  • El código funcional del modo singleton generalmente se escribe en una clase.Si el diseño funcional no es razonable, es fácil violar el principio de responsabilidad única.

8 formas del patrón Singleton

  1. Estilo hambriento (constante estática)

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

  3. Perezoso (no seguro para subprocesos)

  4. Lazy (métodos sincronizados seguros para subprocesos)

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

  6. Doble verificación

  7. clase interna estática

  8. enumerar

Estilo hambriento (constante estática)

Ejemplo de aplicación de estilo hambriento (constante estática), los pasos son los siguientes:

  1. Privatización de constructores (prevenir nuevos)

  2. objeto creado dentro de la clase

  3. Exponer un método público estático. como:getInstance()

  4. Código

ventaja

  • La creación de instancias se completa cuando se carga la clase, lo que evita problemas de sincronización de subprocesos.

defecto

  • No se consigue el efecto de carga diferida, si la instancia no se ha utilizado nunca provocará un desperdicio de memoria.

Código de muestra

Modo singleton : SingletonEHan01.java

public class SingletonEHan01 {

    /**
     * 1. 构造器私有化,外部不能 new
     */
    private SingletonEHan01() {}

    /**
     * 2. 本类内部创建对象实例
     */
    private final static SingletonEHan01 instance = new SingletonEHan01();

    /**
     * 3. 提供公有的静态方法,返回对象实例
     * @return SingletonEHan01
     */
    public static SingletonEHan01 getInstance() {
        return instance;
    }

    /**
     * 4. 代码实现
     */
    public void hello() {
        System.out.println("饿汉式(静态变量):Hello world!");
    }

}

Persona que llama: SingletonPattern.java

public class SingletonPattern {

    public static void main(String[] args) {
        // 1. 饿汉式(静态变量)
        SingletonEHan01 singletonEHan01 = SingletonEHan01.getInstance();
        singletonEHan01.hello();
    }
}

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

Ejemplo de aplicación de estilo hambriento (bloque de código estático), los pasos son los siguientes:

  1. Privatización de constructores (prevenir nuevos)

  2. Esta clase define una variable de instancia estática en el interior y crea un objeto de instancia en el bloque de código estático

  3. Exponer un método público estático. como:getInstance()

  4. Código

ventaja

  • La creación de instancias se completa cuando se carga la clase, lo que evita problemas de sincronización de subprocesos.

defecto

  • No se consigue el efecto de carga diferida, si la instancia no se ha utilizado nunca provocará un desperdicio de memoria.

Código de muestra

Modo singleton: SingletonEHan02.java

public class SingletonEHan02 {

    /** 1. 构造器私有化,外部不能 new */
    private SingletonEHan02() {}

    /** 2. 本类内部定义静态的实例变量 */
    private static SingletonEHan02 instance;

    static {
        // 静态代码块中创建实例对象
        instance = new SingletonEHan02();
    }

    /**
     * 3. 提供公有的静态方法,返回对象实例
     * @return SingletonEHan02
     */
    public static SingletonEHan02 getInstance() {
        return instance;
    }

    /**
     * 4. 代码实现
     */
    public void hello() {
        System.out.println("饿汉式(静态代码块):Hello world!");
    }

}

Persona que llama: SingletonPattern.java

public class SingletonPattern {

    public static void main(String[] args) {
        // 2. 饿汉式(静态代码块)
        SingletonEHan02 singletonEHan02 = SingletonEHan02.getInstance();
        singletonEHan02.hello();
    }
}

Estilo perezoso (el hilo no es seguro, no se puede usar en el desarrollo real)

Ventajas y desventajas

  1. Tiene el efecto de Lazy Loading (carga diferida), pero solo se puede usar bajo un solo hilo

  2. Si en subprocesos múltiples, un subproceso ingresa al bloque de declaración de juicio y otro subproceso también pasa la declaración de juicio antes de que tenga tiempo de ejecutarse, se generarán múltiples instancias en este momento. Por lo tanto, este método no se puede utilizar en un entorno de subprocesos múltiples. if (singleton == null)

en conclusión:

¡En el desarrollo real, no use este método!

Código de muestra

Patrón de singleton: SingletonLanHan01.java

public class SingletonLanHan01 {

    /** 1. 构造器私有化,外部不能 new */
    private SingletonLanHan01() {}

    /** 2. 本类内部定义静态的实例变量 */
    private static SingletonLanHan01 instance;

    /** 3. 提供公有的静态方法,当使用到该方法时才去创建 instance */
    public static SingletonLanHan01 getInstance() {
        // 在多线程下,若多个线程都通过了该判断,便会产生多个实例,所以多线程环境下不推荐使用
        if (instance == null) {
            instance = new SingletonLanHan01();
        }
        return instance;
    }

    /** 4. 代码实现 */
    public void hello() {
        System.out.println("懒汉式(线程不安全):Hello world!");
    }

}

Persona que llama: SingletonPattern.java

public class SingletonPattern {

    public static void main(String[] args) {
        // 3. 懒汉式(线程不安全,实际开发中不推荐使用)
        SingletonLanHan01 singletonLanHan01 = SingletonLanHan01.getInstance();
        singletonLanHan01.hello();
    }
}

Lazy (métodos sincronizados seguros para subprocesos)

Proporciona métodos públicos estáticos y agrega código de procesamiento de sincronización, es decir, synchronized palabras clave, lo que resuelve el problema de la inseguridad de los subprocesos.

Sin embargo, este método es demasiado ineficaz y no se recomienda.

Código de muestra

Modo singleton: SingletonLanHan02.java

public class SingletonLanHan02 {

    /** 1. 构造器私有化,外部不能 new */
    private SingletonLanHan02() {}

    /** 2. 本类内部定义静态的实例变量 */
    private static SingletonLanHan02 instance;

    /**
     * 3. 提供公有的静态方法,加入同步处理代码,解决线程不安全的问题,当使用到该方法时才去创建 instance
     *
     * 注意:正因为加入 synchronized 关键字,则可能导致效率太低,不建议使用
     *
     * */
    public static synchronized SingletonLanHan02 getInstance() {
        if (instance == null) {
            instance = new SingletonLanHan02();
        }
        return instance;
    }

    /** 4. 代码实现 */
    public void hello() {
        System.out.println("懒汉式(线程安全,同步方法):Hello world!");
    }

}

Persona que llama: SingletonPattern.java

public class SingletonPattern {

    public static void main(String[] args) {
        // 4. 懒汉式(线程安全,同步方法)
        SingletonLanHan02 singletonLanHan02 = SingletonLanHan02.getInstance();
        singletonLanHan02.hello();
    }
}

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

Ventajas y desventajas

  • Este método está destinado a mejorar el método anterior de sincronización (es decir, synchronized) , porque la eficiencia del método de sincronización es demasiado baja y se cambia para producir bloques de código instanciados de manera síncrona.

  • Sin embargo, este tipo de sincronización no puede desempeñar el papel de la sincronización de subprocesos.Si bajo subprocesos múltiples, un subproceso ingresaal bloque de declaración de juicio y no ha tenido tiempo de ejecutarlo en el futuro, y otro subproceso también pasa la declaración de juicio, entonces múltiples se generarán subprocesos. Por lo tanto, este método no se puede utilizar en un entorno de subprocesos múltiples. if (singleton == null)

en conclusión:

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

Código de muestra

Modo singleton: SingletonLanHan03.java

public class SingletonLanHan03 {

    /** 1. 构造器私有化,外部不能 new */
    private SingletonLanHan03() {}

    /** 2. 本类内部定义静态的实例变量 */
    private static SingletonLanHan03 instance;

    /** 3. 提供公有的静态方法 */
    public static SingletonLanHan03 getInstance() {
        if (instance == null) {
            /**
             * 加入同步处理代码块
             *
             * 值得注意:
             * 在多线程下,若多个线程都通过了 if (instance == null) 判断,因此便还是会产生多个实例,所以多线程环境下不推荐使用
             */
            synchronized(SingletonLanHan03.class) {
                instance = new SingletonLanHan03();
            }
        }
        return instance;
    }

    /** 4. 代码实现 */
    public void hello() {
        System.out.println("懒汉式(线程安全,同步代码块):Hello world!");
    }

}

Persona que llama: SingletonPattern.java

public class SingletonPattern {

    public static void main(String[] args) {
        // 5. 懒汉式(线程安全,同步代码块)
        SingletonLanHan03 singletonLanHan03 = SingletonLanHan03.getInstance();
        singletonLanHan03.hello();
    }
}

doble control (recomendado)

Ventajas y desventajas

  1. El concepto de doble verificación se usa a menudo en el desarrollo de subprocesos múltiples.Como se muestra en el código, hemos realizado dos if (singleton == null)comprobaciones para garantizar la seguridad de los subprocesos.

  2. De esta manera, el código de instanciación solo necesita ejecutarse una vez, y cuando se accede de nuevo más tarde, se juzga if (singleton == null)y el objeto de instanciación se devuelve directamente, lo que también evita la sincronización repetida de métodos.

  3. Seguridad de subprocesos, carga diferida, alta eficiencia

en conclusión:

¡En el desarrollo real, se recomienda usar este patrón de diseño singleton verificado dos veces!

Código de muestra

Modo Singleton: SingletonDoubleCheck.java

public class SingletonDoubleCheck {

    /** 1. 构造器私有化,外部不能 new */
    private SingletonDoubleCheck() {}

    /** 2. 本类内部使用volatile关键字定义静态的实例变量,volatile 保证可见性和禁止指令重排序 */
    private static volatile SingletonDoubleCheck instance;

    /** 3. 提供公有的静态方法 */
    public static synchronized SingletonDoubleCheck getInstance() {
        // 加入双重检查代码,解决线程不安全的问题,解决懒加载问题
        if (instance == null) {
            synchronized (SingletonDoubleCheck.class) {
                if (instance == null) {
                    instance = new SingletonDoubleCheck();
                }
            }
        }
        return instance;
    }

    /** 4. 代码实现 */
    public void hello() {
        System.out.println("双重检查:Hello world!");
    }
}

Persona que llama: SingletonPattern.java

public class SingletonPattern {

    public static void main(String[] args) {
        // 6. 双重检查
        SingletonDoubleCheck singletonDoubleCheck = SingletonDoubleCheck.getInstance();
        singletonDoubleCheck.hello();
    }
}

Clase interna estática (recomendada)

Cuando se carga la clase externa, la clase interna estática no se cargará, lo que asegura el problema de la carga diferida.

Cuando se llama al método getInstance(), se creará una instancia de la clase interna estática y se utilizarán las variables estáticas de la clase interna estática.Cuando la JVM está cargando la clase, es segura para subprocesos.

Ventajas y desventajas

  1. Este método utiliza el mecanismo de carga de clases para garantizar que solo haya un hilo al inicializar la instancia.

  2. En el método de clase interna estática, cuando se carga la clase externa, no se instanciará inmediatamente, pero cuando sea necesario, se llamará al método para cargar la clase interna, completando así la instanciación getInstance()de la clase externa.

  3. Las propiedades estáticas de la clase solo se inicializarán cuando la clase se cargue por primera vez, por lo que aquí, la JVM nos ayuda a garantizar la seguridad del subproceso. Cuando la clase se inicializa, otros subprocesos no pueden ingresar.

  4. Ventajas: evite la inseguridad del subproceso, use características estáticas de clase interna para lograr una carga diferida, alta eficiencia

en conclusión:

¡Uso recomendado!

Código de muestra

Patrón Singleton: SingletonInnerClass.java

public class SingletonInnerClass {

    /** 1. 构造器私有化,外部不能 new */
    private SingletonInnerClass() {}

    /** 2. 本类内部使用volatile关键字定义静态的实例变量 */
    private static volatile SingletonInnerClass instance;

    /** 3. 提供公有的静态方法 */
    public static synchronized SingletonInnerClass getInstance() {
        // 直接返回静态内部类的静态变量
        return SingletonInstance.INSTANCE;
    }

    /** 4. 提供一个静态内部类 */
    private static class SingletonInstance {
        private static final  SingletonInnerClass INSTANCE = new SingletonInnerClass();
    }

    /** 5. 代码实现 */
    public void hello() {
        System.out.println("静态内部类:Hello world!");
    }
}

Persona que llama: SingletonPattern.java

public class SingletonPattern {

    public static void main(String[] args) {
        // 7. 静态内部类
        SingletonInnerClass singletonInnerClass = SingletonInnerClass.getInstance();
        singletonInnerClass.hello();
    }
}

enumeración (recomendado)

El uso de la enumeración 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.

en conclusión:

¡Uso recomendado!

Código de muestra

Patrón Singleton: SingletonEnum.java

public enum SingletonEnum {

    /** 1. 实例化对象 */
    INSTANCE;

    /** 2. 代码实现 */
    public void hello() {
        System.out.println("枚举:Hello world!");
    }

}

Persona que llama: SingletonPattern.java

public class SingletonPattern {

    public static void main(String[] args) {
        // 8. 枚举
        SingletonEnum.INSTANCE.hello();
    }
}

Patrón singleton en JAVA

java.lang.Runtime

conclusión

1. Para obtener más patrones de diseño, consulte la columna [Patrones de diseño]

2. Se pueden descargar códigos de muestra relevantes:  Ejemplos de patrones de diseño comunes en Java

PD: [  Ejemplo de patrones de diseño comunes  en Java] ha incluido  el código involucrado en la columna [Patrón de diseño]  . Si lo ha descargado antes, no necesita descargarlo de nuevo ~

Si el contenido anterior es incorrecto o debe complementarse, solicite más consejos y se actualizará y corregirá a tiempo ~

Los comentarios son bienvenidos ~ Gracias por sus elogios ~

Supongo que te gusta

Origin blog.csdn.net/pjymyself/article/details/121929248
Recomendado
Clasificación