El patrón de singleton es el más fácil de entender y la forma más fácil de el código escrito a mano en el patrón de diseño, pero no hay muchos puntos de conocimiento involucrados, por lo que a menudo se usa como una pregunta de entrevista. En general, los solteros se escriben de cinco maneras: perezoso, hambriento, bloqueo de doble verificación, clases internas estáticas y enumeración. Para registrar el proceso de aprendizaje, se han compilado varios métodos comunes de escritura singleton.
Bronce 5: (cargado de perezoso, pero el hilo no es seguro)
Cuando se le preguntó sobre la implementación de un patrón de singleton, la primera reacción de muchas personas es escribir el siguiente código, incluidas las mismas enseñanzas en los libros de texto.
clase pública Singleton {instancia privada de singleton static; private singleton () {} public static singleton getInstance () {if (instance == null) {instancia = new Singleton (); } instancia de retorno; }}Este código es simple y directo, y utiliza el modo de carga retrasada, pero los subprocesos no son seguros. Llamar al método getInStance () en un entorno múltiple puede hacer que múltiples subprocesos ingresen el bloque de código del programa de la instrucción IF.
Estilo perezoso: sincronizado (cargado de perezoso, seguro de hilo, pero no eficiente)
Para resolver el problema anterior, la forma más fácil es establecer todo el método getInstance () para sincronizar.
clase pública Singleton {instancia privada de singleton static; private singleton () {} public static sincronizado sincronizado Singleton getInstance () {if (instance == null) {instancia = new Singleton (); } instancia de retorno; }}Aunque es una carga segura y retrasada, no es eficiente. Porque en cualquier momento solo puede haber un hilo llamando al método getInstance (). Sin embargo, la operación sincronizada solo debe ser necesaria en la primera llamada, es decir, cuando el objeto de instancia de Singleton se crea por primera vez. Este patrón hace que solo un hilo acceda al método getInstance () a la vez incluso después de que se crea el singleton, lo que puede conducir a posibles problemas de rendimiento. Esto conduce a un bloqueo de doble verificación.
Estilo hambriento: campo final estático (no cargado de perezoso)
Este método es muy simple, porque la instancia de un singleton se declara como estática final y se inicializa cuando la clase se carga en la memoria por primera vez, por lo que crear un objeto de instancia es seguro de hilo (garantizado por la implementación JVM).
public class Singleton {// Inicializar la instancia de Singleton final estática privada = new Singleton (); Private Singleton () {} public static singleton getInstance () {// singleton con instancia de retorno de fábrica estática; }}No es un modo de carga perezoso, la instancia se inicializará desde el principio después de cargar la clase, incluso si el cliente no llama al método getInstance (). Esto conducirá a algunas restricciones de uso: por ejemplo, la creación de una instancia de singleton depende de parámetros o archivos de configuración. Antes de GetInstance (), se debe llamar a un determinado método para establecer parámetros, de modo que no se utilice este método de escritura singleton. Métodos similares incluyen:
public class Singleton {public static static singleton instancia = new Singleton (); // Singleton con Field Public Field Singleton () {}} // <java efectivo> La página 14 dice la diferencia entre los dosBloqueo de doble verificación + volátil (LazyLoad, ausente de subprocesos, pero oscuro)
El patrón de bloqueo a doble verificación es un método de bloqueo utilizando bloques sincrónicos. Los programadores lo llaman un bloqueo de doble verificación porque habrá dos instancias de verificación == NULL, una vez fuera del bloque de sincronización y una vez dentro del bloque de sincronización. ¿Por qué necesitamos verificar nuevamente en el bloque de sincronización? Debido a que múltiples hilos pueden ingresar si están fuera del bloque de sincronización juntos, si no se realiza una verificación secundaria en el bloque de sincronización, se generarán objetos de instancia múltiples.
public static singleton getSingleton () {if (instance == null) {// sincronizado solo verificado (singleton.class) {if (instance == null) {// double checked instance = new singleton (); }}} instancia de retorno;}Este código se ve perfecto, pero desafortunadamente es problemático. Lo principal es la oración instancia = new Singleton (). Esta no es una operación atómica. De hecho, esta oración en JVM hace aproximadamente las siguientes 3 cosas.
Sin embargo, hay optimización del reordenamiento de instrucciones en el compilador JIT de JVM. En otras palabras, no se puede garantizar el orden del segundo y tercer paso anterior, y la orden de ejecución final puede ser 1-2-3 o 1-3-2. Si es lo último, se evitará por el hilo 2 antes de que la ejecución de 3 y 2 no se ejecute. En este momento, la instancia ya no es nula (pero no inicializada), por lo que Thread 2 devolverá directamente la instancia, luego la usará y luego informará naturalmente un error. Para hacer esto, necesitamos declarar la variable de instancia como volátil.
Class Public Singleton {instancia de singleton static static volátil privada; // Declarar como volátil Singleton () {} public static singleton getsingleton () {if (instance == null) {sincronizado (singleton.class) {if (instance == null) {instancia = nueva singleton (); }} instancia de retorno; }}Sin embargo, es importante tener en cuenta que todavía hay problemas con el bloqueo de doble verificación del volátil en versiones antes de Java 1.5. Este problema solo se solucionó en Java 1.5, por lo que puede usar volátiles después de eso.
Clase interna estática: IODH, titular de inicialización-on-demanda
Este patrón combina las clases internas estáticas de Java y el conocimiento de bloqueo de sincronización predeterminado de múltiples subprocesos, e implementa hábilmente la carga de latencia y la seguridad de los subprocesos.
public class Singleton {private singleton () {} private static class Lazyholder {private static final singleton instancia = new Singleton (); } public static singleton getInstance () {// De Wikipedia Devuelve lazyholder.instance; }}Una clase interna estática es equivalente a la parte estática de su clase externa. Sus objetos no dependen de objetos de clase externos, por lo que se pueden crear directamente. Las clases internas estáticas solo se reproducirán cuando se usen por primera vez.
Bloqueo de sincronización predeterminado multiproceso
Como todos sabemos, en el desarrollo múltiple, para resolver el problema de concurrencia, es principalmente usar sincronizado para agregar mutexes para el control de sincronización. Pero en algunos casos, el JVM ya realiza implícitamente la sincronización para usted, y en estos casos no hay necesidad de realizar manualmente el control de sincronización. Estas situaciones incluyen :
1. Al inicializar los datos mediante un inicializador estático (inicializador en un campo estático o en un bloque estático {})
2. Al acceder al campo final
3. Al crear un objeto antes de crear un hilo
4. Cuando el hilo puede ver el objeto que procesará
Enumer
A partir de Java 1.5, simplemente escriba un tipo enum que contenga un solo elemento:
public enum singleton {instancia;}Este método es funcionalmente similar al método de dominio público, pero es más conciso y proporciona un mecanismo de serialización de forma gratuita, evitando absolutamente la instanciación múltiple, incluso cuando se enfrenta a los complejos ataques de serialización o reflexión. Aunque este enfoque no ha sido ampliamente adoptado, los tipos de enumeración de elementos individuales se han convertido en la mejor manera de implementar Singleton.
----------------------------------------------------------------------------------------------------------------------------
1. ¿Cuáles son los detalles de la final estática
2. ¿La inicialización de la asignación en el campo estático en secuencia y el bloque de código estático?
3. Cómo escribir un patrón singleton para clases internas estáticas
4. ¿Los ejemplos en el análisis y la aplicación de patrones de diseño de Java EE realmente tienen un efecto perezoso?
Lo anterior es todo el contenido de este artículo. Espero que el contenido de este artículo sea de ayuda para el estudio o el trabajo de todos. ¡También espero apoyar a Wulin.com más!