Entrevista de modo único de Java

El siguiente artículo es de la  cuenta pública de WeChat Xiaoha Learn Java , autor AllenJiang

El patrón singleton es el patrón de diseño más simple entre los 23 tipos de GOF (patrones de diseño) y el patrón de diseño más clásico. En la entrevista de Java, se puede decir que es un punto de conocimiento necesario. A continuación, hablemos al respecto en detalle.

Entrevistador: ¿Está familiarizado con los patrones de diseño? ¿Qué patrones de diseño has usado en tu trabajo?

Solicitantes: hay modo singleton, modo fábrica, modo cadena de responsabilidad, modo agencia comúnmente utilizado en el trabajo ...

Entrevistador: ¡Oh! Ahora que mencionó el patrón singleton, ¿cuál diría que es el patrón singleton? ¿Por qué usar el modo singleton? ¿Hay varios modos singleton? ¿A qué debo prestar atención al usarlo?

En general, el entrevistador corta el punto de conocimiento del modo singleton a través del diálogo anterior.

¿Cuál es el patrón singleton?

En términos simples, el modo de columna única es asegurar que solo haya una instancia de un objeto en la memoria durante la vida del programa. Es decir, solo hay un objeto para una clase.

¿Por qué usar el modo singleton?

Usar el modo singleton no es más que mejorar el rendimiento de ejecución del código, podemos hablar sobre los siguientes dos puntos:

  • 1. Ahorre recursos de memoria

  • 2. Ahorre tiempo (tiempo para asignar objetos)

El primero es ahorrar recursos de memoria. Para algunos objetos grandes en el programa, estos objetos ocupan una gran cantidad de memoria. La creación frecuente no solo aumenta la sobrecarga de memoria, sino que también consume mucho tiempo de asignación de memoria. Además, activará GC (recolección de basura) frecuente, GC Aumentará el tiempo de sobrecarga. En casos graves, también puede producirse un GC completo, lo que puede bloquear el hilo principal del programa. Estos son intolerables. El modelo de una sola fila nació en esta situación.

¿Hay varios patrones singleton?

Normalmente decimos que cinco tipos son suficientes, pero para mostrar nuestro amplio conocimiento, podemos decir esto:

Candidatos: Hay 7 tipos de modelos de singleton subdivididos, pero estrictamente hablando solo hay 5 tipos. Déjame hablar sobre las siete subdivisiones:

El primero: hilo perezoso e inseguro

public class Singleton {  

  private static Singleton instance;  

  private Singleton (){}   

  public static Singleton getInstance() {  
  if (instance == null) {  
    instance = new Singleton();}  
  return instance;  
  }  

Este método de escritura es de carga lenta. Lo fatal es que en el caso de subprocesos múltiples, habrá instancias múltiples de objetos Singleton instanciados.

El segundo tipo: perezoso, seguro para hilos

public class Singleton {
  private static Singleton instance;
  private Singleton (){}

  public static synchronized Singleton getInstance() {
    if (instance == null) {
      instance = new Singleton();}
    return instance;
  }
}

Esta forma de escribir funciona bien en un entorno de subprocesos múltiples y también tiene la ventaja de una carga lenta, pero, desafortunadamente, la eficiencia es muy baja y no se requiere sincronización en el 99% de los casos.

El tercer tipo: chino hambriento

public class Singleton {  

   private static Singleton instance = new Singleton();  

   private Singleton (){}

   public static Singleton getInstance() {  
    return instance;  
}

Este método se basa en el mecanismo de carga de clases de Java para evitar el problema de la sincronización de varios subprocesos, pero debido a esto, la instancia se instancia cuando se carga, y hay muchas razones para la creación de instancias. A veces, no estamos dispuestos a usarla Instanciado Y el modo singleton la mayor parte de la instanciación es llamar al método getInstance (), que viola el diseño de carga diferida.

Nota 1: El entrevistador también puede preguntarle: ¿Cuándo se inicializa la instancia?

La instancia se inicializará cuando se cargue la clase. Cuando se trata de cargar la clase, no hay una restricción obligatoria en la especificación de la máquina virtual JVM a qué hora específica cargar la clase, pero con respecto a la inicialización de la clase, la máquina virtual estipula estrictamente que solo hay Hay 4 situaciones, respectivamente, cuando se especifican los siguientes 4 bytecodes:

  • 1. nuevo 

  • 2. getStatic 

  • 3. putStatic 

  • 4. invokeStatic 

Al encontrar los códigos de designación de 4 bytes anteriores, si la clase no se ha inicializado, primero debe activar su inicialización.

En cuanto a cuándo generar las 4 instrucciones anteriores, corresponden a los siguientes escenarios:

  • 1. Use la nueva  palabra clave para crear una instancia del objeto ==> correspondiente a la nueva instrucción ;  

  • 2. Lea el campo estático de una clase (excepto el campo estático modificado por final y coloque el resultado en el grupo constante en tiempo de compilación) ==> correspondiente a la instrucción getStatic ; 

  • 3. Establezca un campo estático de la clase (excepto el campo estático modificado por final y coloque el resultado en el grupo constante en tiempo de compilación) ==> corresponde a la instrucción putStatic ; 

  • 4. Llame a un método estático de una clase ==> correspondiente a la instrucción invokeStatic ; 

Nota 2: ¿El entrevistador también puede preguntarle a su mecanismo de carga de clase JVM?

En este momento, puede hablar sobre el modelo de delegación principal del cargador de clases, que no se describirá aquí.

Cuarto tipo: hombre hambriento, variante

public class Singleton {  
    private Singleton instance = null;  

    static {  
      instance = new Singleton();
    }  

    private Singleton (){}

    public static Singleton getInstance() {  
    return this.instance;  
    }  

Aquí, el bloque estático se usa para crear instancias del objeto, que en realidad es similar al tercero.

Quinto: clase interna estática

public class Singleton {  

    private static class SingletonHolder { 
      private static final Singleton INSTANCE = new Singleton();
    }  

    private Singleton (){}

    public static final Singleton getInstance() {  
      return SingletonHolder.INSTANCE;  
    }  

Este método también utiliza el mecanismo classloder para garantizar que solo haya un subproceso al inicializar la instancia. Es diferente del tercer y cuarto método (muy poca diferencia): el tercer y cuarto método son tan largos como la clase Singleton Si se carga, la instancia se instanciará (sin el efecto de carga diferida) y, de esta forma, se cargará la clase Singleton y es posible que la instancia no se inicialice. Debido a que la clase SingletonHolder no se usa activamente, solo cuando se muestra que se llama al método getInstance, se muestra la clase SingletonHolder y se instancia la instancia. Imagine que si instanciar una instancia consume recursos, quiero que retrase la carga. Por otro lado, no quiero crear una instancia cuando se carga la clase Singleton, porque no puedo asegurar que la clase Singleton pueda usarse activamente en otro lugar Está cargado, entonces es obviamente inapropiado crear una instancia en este momento. En este momento, este método es bastante razonable en comparación con los métodos tercero y cuarto.

Sexto: enumeración

 public enum Singleton {  
   INSTANCE;  
   public void whateverMethod(){}  
 } 

Este método es defendido por el autor de "Java eficaz" Josh Bloch. No solo evita los problemas de sincronización multihilo, sino que también evita automáticamente los ataques de serialización / deserialización y los ataques de reflexión (las clases de enumeración no se pueden generar por reflexión).

Séptimo: bloqueo de doble verificación (DCL)

public class Singleton {  

    private volatile static Singleton singleton;  

    private Singleton (){}   

    public static Singleton getSingleton() {  
    if (singleton == null) {  
      synchronized (Singleton.class) {  
      if (singleton == null) {  
        singleton = new Singleton();}  
     }  
   }  
   return singleton;  
   }  
 } 

Esta es una versión mejorada del segundo método, comúnmente conocido como bloqueo de doble verificación. Al agregar una capa de juicio fuera del sincronizado, ya no puede ingresar el bloque sincronizado una vez que se crea el objeto. Este esquema no solo reduce la granularidad de la cerradura, garantiza la seguridad de la rosca, sino que también mejora enormemente el rendimiento.

También es necesario hablar de este papel volidate palabra clave es evitar que el reordenamiento de instrucciones JVM, el hormigón puede leer mi otro artículo "Tienes que conocer la palabra clave volátil" . 

Resumen

Pero en términos generales, el primer tipo no es un caso único, el cuarto tipo y el tercer tipo es un tipo, si se cuenta, el quinto tipo también se puede escribir por separado. Por lo tanto, el caso único general se escribe de cinco maneras.

  • 1. un hombre perezoso

  • 2. Hombre hambriento

  • 3. Doble bloqueo de verificación (DCL)

  • 4. Enumeración

  • 5. Clase interna estática

  •  

Supongo que te gusta

Origin www.cnblogs.com/yujian0817/p/12745698.html
Recomendado
Clasificación