¿Qué es una versión de seguridad, cómo asegurar la inicialización?

prefacio

Muchas veces necesitamos compartida a través de hilos de objeto si la existencia concurrente tenemos que los objetos compartidos de una manera segura para los subprocesos, momento en el que se trata de cómo nos aseguramos el objeto se inicializa para llevar a cabo la liberación de seguridad, esta sección de nuestro debate futuro seguro para inicialización, publicación segura, el papel si hay errores, pero también buscan la crítica.

versión de seguridad

De acuerdo con los términos normales de lógica narrativa, lo primero que debe discutir la forma de inicialización segura, y luego para liberar el análisis de la seguridad, por aquí, tomamos flashback, para discutir cuestiones que han surgido a través de publicaciones no relacionadas con la seguridad, y, finalmente, cómo dar ser seguros para la inicialización, como sigue, por ejemplo, tenemos un modelo único caso.

público  de clase SynchronizedCLFactory {
     privado instancia Singleton; 

    pública Singleton get () {
         sincronizado ( este ) {
             si (== ejemplo nula ) { 
                instancia = nueva Singleton (); 
            } 
            Devolver ejemplo; 
        } 
    } 
} 

Pública  clase Singleton { 

}

Según lo previsto para la obtención método de instancia Singleton pública, mantenemos un hilo de seguridad mediante la sincronización de clave, no importa cuántos hilos en una solicitud Singleton, independientemente de cómo el estado actual de todas las discusiones obtendrá la misma instancia de Singleton, Singleton inicialización Singleton se produce cuando la primera solicitud, pero no se produjo durante la inicialización de la clase Singleton, en cuanto a si o no el foco de nuestra atención inicialización perezosa, mientras que el bloque de código se bloqueará de manera que Singleton intento estado para mantener los gastos generales al mínimo. Para ser más preciso para que un solo caso debe tener una instancia única, que DCL (Double Check bloqueo), podemos transformar la siguiente:

público  de clase SynchronizedCLFactory {
     privado instancia Singleton; 

    pública Singleton get () {
         si (== ejemplo nula ) {
             sincronizado ( este ) {
                 si (== ejemplo nula ) { 
                    instancia = nueva Singleton (); 
                } 
            } 
        } 
        Regresar ejemplo; 
    } 
} 

Pública  clase Singleton { 

}

Tal vez pensamos que después de la finalización con éxito de la primera sentencia paso, se puede inicializar correctamente la instancia Singleton, a continuación, lo puede devolver, de hecho, este entendimiento es erróneo, porque Singleton hilo instancia es totalmente visible sólo para la construcción, pero no puede garantizar que en otros hilos el derecho de ver la instancia Singleton, se debe a que existe una competencia e inicializar el hilo instancia Singleton, por otra parte, aunque el final ha sido una instancia no nula, esto no significa que podemos observar adecuadamente su estado interno, desde la perspectiva JMM, constructor de Singleton la inicialización de almacenar y leer nada sucedió entre el campo Singleton, también podemos ver, volver a leer la sincronización sin ningún juicio en el primer paso y el último paso, uno de los propósitos es permitir que el modelo de memoria de Java para lectura de reordenación ordinario (reordenamiento), de lo contrario la sobrecarga de rendimiento se puede imaginar, en términos de memoria, la operación de lectura se puede escribir por la observación competencia desordenada, que se determina para cada operación de lectura, y con qué otro la operación de lectura no tiene nada que ver con la misma posición, en el ejemplo anterior, esto Esto significa que a pesar de que el primer paso puede ser determinada por la lectura de ejemplos de no vacío, pero entonces el código continúa para devolverlo, y después lee un valor original, y se puede leer devolverá una instancia vacía. liberación de seguridad y liberación general difieren en un punto clave: liberación de seguridad todos los valores escritos antes de la liberación de todos los hilos anotaron objeto observado es visible, se simplifica en gran medida de las acciones, comandos, etc. JMM las normas acordadas. Así que vamos a s consiguen la acción antes de la próxima versión de seguridad es seguro para inicialización.

Seguro para inicialización

Al inicializar el objeto compartido debe ser construida sólo por su acceso hilo, pero una vez que se complete la inicialización, se puede liberar de forma segura el objeto aunque el objeto es visible a otros hilos, Java modelo de memoria (JMM) permite que múltiples hilos en la inicialización Sin embargo, el objeto observado antes del final del principio, por lo tanto, se debe evitar escribir un objeto de programa lanzado parcialmente inicializado, las reglas prohíben la publicación de miembro se opone parcialmente inicializado antes del final de la referencia de inicialización a una instancia, en especial para la seguridad del código multiproceso durante la referencia de objetos constructores no dejan que este escape, con el fin de evitar que el objeto actual de esta referencia para escapar de su constructor. El código de ejemplo por debajo de un configurado initialize clase método Holder objeto Foo, objeto Holder constructor inicializa sus campos.

público  de clase Foo {
     privada titular Titular; 

    pública titular getHolder () {
         retorno titular; 
    } 

    Pública  vacío initialize () { 
        titular = nuevo titular (42 ); 
    } 
} 

Pública  clase Holder {
     privada  int n; 

    público Holder ( int n) {
         este .n = n; 
    } 
}

Si el método getHolder Holder clase de acceso de hilo utilizado antes de la realización del procedimiento de inicialización, se observará el hilo que el campo del titular no se ha inicializado, si el siguiente método initialize se llama un hilo, mientras que otro método llamado getHolder, el segundo hilo se puede observar uno de estos tipos de situaciones: un soporte de referencia está vacío, Holder objeto completamente instanciado 42 es N, N haber objeto Holder no inicializado parcialmente inicializado, en la que n es 0 campo contiene los valores predeterminados, la razón principal es que, JMM permite al compilador para asignar un portaobjetos nueva inicialización antes de que el nuevo objeto Holder , y una referencia a la memoria asignada al titular del campo, en otras palabras, el compilador puede escribir y las instancias de objeto Holder Initialize del campo de escritura (es decir this.n = n) para reordenar la prioridad que el primero parece que habrá una competición, durante el cual otros hilos instancias de objeto del sostenedor pueden observarse parcialmente inicializan. Antes de constructor de objeto ha completado su inicialización, no debe publicar una referencia a la instancia del objeto, esto conducirá a esta fuga de referencia durante la construcción de objetos. Seguimos leyendo cómo llevar a cabo correctamente la inicialización de seguridad.

mecanismo de sincronización

Utilizamos sincronización puede prevenir la liberación de parte de la inicialización de la referencia de objeto, como sigue:

público  de clase Foo {
     privada titular Titular; 

    pública  sincronizado titular getHolder () {
         retorno titular; 
    } 

    Pública  sincronizado  void initialize () { 
        titular = nuevo Holder (42 ); 
    } 
}

Vamos a inicializar y obtener una instancia del soporte de las variables anteriormente mencionadas para sincronizar estos dos métodos, para asegurarse de que no pueden realizar al mismo tiempo, si un hilo pasa a inicializar método se llama antes de un método getHolder hilo, el método initialize de sincronización siempre será completado primero, este porque synchornized palabras clave entre los dos hilos para establecer una relación de antemano (que ocurre antes) se produjo, por lo que la llamada al método getHolder hilo va a ver un objeto totalmente inicializado o no objeto Holder, es decir, que contiene titular referencia nula, este método asegura que los miembros de los miembros inmutables y variables liberación del todo correcto.

palabra clave final

JMM asegurar el campo completo de la declaración de seguridad valor de inicialización final emitida a cada hilo, el hilo lee estos valores en algún momento no antes del final del constructor de objetos, el siguiente ejemplo de código de tiempo:

público  de clase Foo { 
    
    privado  última titular Titular; 
    
    público   Foo () { 
        titular = nuevo Holder (42 ); 
    } 

    Pública titular getHolder () {
         retorno titular; 
    } 
    
}

Sin embargo, esta solución requiere una nueva instancia titular titular de la asignación en la conducta del constructor de Foo, de acuerdo con la especificación del lenguaje Java, leer el campo final durante la construcción: Leer la estructura de rosca del objeto al campo final se basa en general se produce antes de (que ocurre antes) constructor inicializa las reglas del campo de clasificación, si se lleva a cabo después de que el campo se establece en el constructor leer, verá el campo final se le asigna un valor, de lo contrario, verá que el valor por defecto, por lo tanto, los casos, antes de que se complete la clase Foo constructor, el titular debería citarse permanecen inéditos.

combinación final de palabras clave y thread-safe

Sabemos que hay algunas clases de colección proporcionan acceso seguro para subprocesos al elemento que contiene, cuando Holder objeto en esta colección, se puede asegurar que antes de que sea visible referencia se inicializa completamente en Java, como vector colección.

público  de clase Foo { 

    privados  finales vector <Holder> titulares; 

    público Foo () { 
        titulares = nuevo vector <> (); 
    } 

    Pública titular getHolder () {
         si (holders.isEmpty ()) { 
            initialize (); 
        } 
        Devolver   holders.elementAt (0 ); 
    } 

    Pública  sincronizado  vacío initialize () {
         si (holders.isEmpty ()) { 
            holders.add ( nuevo titular (42 )); 
        } 
    }
}

El campo titular se declara como final, para asegurarse de que siempre crea objetos Titular antes de cualquier acceso a la colección del vector, se puede sincronizar llamando a que se inicie la método initialize con seguridad, para garantizar que sólo agregar un objeto Titular al vector, si método initialize se llama antes de entonces el método getHolder eliminando así la posibilidad citada llamando método condicionalmente initialize a puntero evitar null, aunque contexto de invocación de método estaVacia método getHolder Nunca se sincroniza (permite que las decisiones múltiples hilos deben ser llamados para inicializar ) lleva a cabo, pero todavía puede dar lugar a condiciones de competencia, las condiciones de competencia y esto puede conducir a añadir un segundo conjunto de objetos al vector, inicializar el método de sincronización de comprobar si el soporte todavía está añadiendo nuevo titular ante el objeto está vacío, y como máximo un hilo puede ejecutar el método initialize, por lo tanto, sólo el primer hilo de método initialize de ejecución para ver un conjunto vacío de vector, y el método getHolder puede ignorar ninguna sincronización en sí.

inicialización estática

Vamos a titular de campo estático de inicialización, para asegurar que las referencias a objetos que el campo se ha inicializado por completo antes de su referencia se hace visible, de la siguiente manera:

clase Foo { 

    privado  estática  final de Holder titular = nuevo Holder (42 ); 

    pública  estática titular getHolder () {
         retorno titular; 
    } 
}

Necesitamos campo titular está declarada como final, para registrar la invariancia de la clase, de acuerdo con la especificación del lenguaje Java, los campos static final: Asegura norma de inicialización de clase que cualquier campo de lectura estática de la rosca se sincronizará con la inicialización estática de la clase, que es con la única ubicación de campo final estático, por lo tanto, para los campos estáticos finales, que no requiere reglas especiales JMM.

Los objetos inmutables (palabra clave final, referencia volátil)

JMM garantía emitida antes de que el objeto se vuelve visible, todos los objetos de campo finales están totalmente inicializado, por lo que la declaración final por clase se convierte en titular inmutable, mientras que el campo titular se declara tan volátil para asegurar la visibilidad de las referencias compartidas a objetos inmutables sexo sólo después inicializa completamente Holder, con el fin de asegurar que cualquier subproceso llama a métodos getHolder se pueden encontrar en el soporte de referencia.

clase Foo { 

    privado  volátil titular Titular; 

    pública titular getHolder () {
         retorno titular; 
    } 

    Pública  vacío initialize () { 
        titular = nuevo titular (42 ); 
    } 
} 

Última  clase Holder {
     privado  última  int n; 

    público Holder ( int n) {
         este .n = n; 
    } 
}

Como titular declara como volátil y clase titular es inmutable, si el campo auxiliar no es una variable, entonces la violación garantizar la visibilidad compartida inmutable referencias a objetos, se recomienda proporcionar un método de fábrica estática pública para devolver una nueva instancia del titular, este método permite crear la instancia de titular en un constructor privado. Los objetos inmutables son siempre Hilo de seguridad, volátil asegurar su visibilidad para que los destinatarios son capaces de liberación de seguridad completamente correcta.

objetos mutables (Hilo de seguridad y referencias volátiles)

Cuando titular pero aunque la variable thread-safe, puede ser liberado de forma segura un comunicado a través del campo en la clase titular Titular volátil:

clase Foo { 

    privado  volátil titular Titular; 

    pública titular getHolder () {
         retorno titular; 
    } 

    Pública  vacío initialize () { 
        titular = nuevo titular (42 ); 
    } 
} 

Última  clase Holder {
     privado  volátil  int n; 

    privada  última bloqueo Objeto = nueva Object (); 

    público Holder ( int n) {
         este .n = n; 
    } 

    Pública  nulaSETN ( int n) {
         sincronizada (bloqueo) {
             este .n = n; 
        } 
    } 
}

Deben sincronizarse para garantizar la visibilidad de la variable miembro después de la liberación inicial, porque el objeto Holder puede cambiar el estado después de su construcción, la forma SETN sincronización para garantizar la visibilidad del campo n si el tipo de Holder de sincronización es incorrecta, la clase Foo el titular será declarada única garantía liberación inicial titular visibilidad volátil, se asegurará la visibilidad de visibilidad excluir posterior cambio de estado, por lo tanto, no es suficiente para publicar referencia solamente variable no está seguro para subprocesos objetos, si el campo de clase Foo titular no declarado como volátil, debe ser n campo está declarada como volátil, para inicializar el n y el soporte de establecer una relación (que ocurre antes) que ocurren previo por escrito entre el campo titular sólo cuando la persona que llama no se puede confiar (Foo clase) cuando la clase Holder declaró volátil única necesidad de hacer esto, porque la clase Holder se declara como clases públicas, por lo que utiliza bloqueo patentado para la sincronización, utilizando objetos de bloqueo final privado a sincronizar pueden código no confiable.

 

Entonces la pregunta es, puede declarar un objeto de volátiles proporcionan la misma garantía y declaran tipos básicos de volátil? Si tiene una variable de objetos compatibles con el proceso o si tenemos una muy buena razón para ser declarado como volátil que? objetos declarados no volátiles pueden estar provistos de los tipos básicos de declaración volátil para proporcionar la misma garantía para objetos variables debe prohibirse declarada como volátil, pero establecer la sincronización, ya que la sincronización principal énfasis es atómica, siguieron la visibilidad, pero volátil es la principal garantía de visibilidad, por lo que no habrá trampas cuando se utiliza con objetos variables y volátil (sólo cuando el objeto compartido está totalmente construida o inmutable, podemos utilizar la versión de seguridad volátil), de manera que se infiere de la exactitud de la visibilidad , se debe evitar el uso de variables volátiles, volátiles se producen utiliza principalmente para asegurar la visibilidad de los objetos los que hace referencia, o se utiliza para identificar los eventos del ciclo de vida importantes (tales como la inicialización o apagado) de.

 

Si un objeto no es inmutable, entonces debe ser seguro para publicar, la forma de garantizar que el estado de otros hilos pueden ver el comunicado de objeto debe ser resuelto a su lanzamiento destino otros hilos para modificar la visibilidad del tema, con el fin de asegurar la liberación del objeto, el objeto referencias y el estado del objeto debe estar en el otro hilo es visible, el objeto derecho creado por: referencia de objeto de inicialización initialize estática (porque asegura JMM que el objeto compartido está totalmente reconstruido), la referencia al objeto almacenado en volátil o AtomicReference, la referencia de objeto a un objeto almacenado creado correctamente las referencias finales objeto de dominio de protección mecanismo de bloqueo.

resumen

Java permite que los objetos de la manera en que siempre publicamos una declaración a la seguridad que nos está provisto con la oportunidad de inicialización segura, inicializar la seguridad del objeto observado todos los lectores puedan ver todos los valores en la inicialización del constructor, con independencia de que el objeto se libera de forma segura Si todos los objetos campos es final, y el constructor para inicializar el objeto no se escapa, entonces el modelo de memoria de Java (JMM) proporcionará una fuerte garantía más en esto, siempre hay que tener en cuenta el objeto compartido durante el lanzamiento de seguridad antes hay que evitar ser parte de la inicialización que es objetos creados localmente.

Supongo que te gusta

Origin www.cnblogs.com/CreateMyself/p/12459141.html
Recomendado
Clasificación