La comprensión en profundidad del modelo de memoria de Java (cuatro) - volátil

Las características de volátiles

Cuando declaramos variables compartidas a ser volátil, de lectura / escritura será muy especial para esta variable. Una buena manera de entender las características volátiles son: una sola lectura de las variables volátiles / escritura, utilizando el mismo monitor como un bloqueo para la operación de lectura / escritura solo hecho de forma sincronizada. Deje ilustrado con ejemplos específicos, consulte el siguiente código de ejemplo:

class VolatileFeaturesExample {
    volatile long vl = 0L;  // 使用 volatile 声明 64 位的 long 型变量 

    public void set(long l) {
        vl = l;   // 单个 volatile 变量的写 
    }

    public void getAndIncrement () {
        vl++;    // 复合(多个)volatile 变量的读 / 写 
    }


    public long get() {
        return vl;   // 单个 volatile 变量的读 
    }
}

Supongamos que hay varios subprocesos llamar los tres métodos anteriores programa, este programa es semánticamente equivalente y los procedimientos siguientes: 

class VolatileFeaturesExample {
    long vl = 0L;               // 64 位的 long 型普通变量 

    public synchronized void set(long l) {     // 对单个的普通 变量的写用同一个监视器同步 
        vl = l;
    }

    public void getAndIncrement () { // 普通方法调用 
        long temp = get();           // 调用已同步的读方法 
        temp += 1L;                  // 普通写操作 
        set(temp);                   // 调用已同步的写方法 
    }
    public synchronized long get() { 
    // 对单个的普通变量的读用同一个监视器同步 
        return vl;
    }
}

Como se muestra, un solo ejemplo de lectura por encima de una variable volátil operaciones de programa / escritura, y una lectura general de la variable / operaciones de escritura utilizan el mismo bloqueo del monitor para sincronizar, el mismo efecto entre los mismos.

sucede-antes de garantías de liberación de bloqueo del monitor regular y el acceso a la visibilidad monitor de memoria entre los dos hilos del monitor, que medios de lectura de una variable volátil, siempre capaz de ver (cualquier hilo) de esta variable volátil final por escrito.

Monitor de la semántica de bloqueo determina la ejecución de una sección crítica de código atómica. Esto significa que incluso un 64-bit de largo y de tipo variable doble, con tal de que es una variable volátil, la variable se leen atómica. Si una pluralidad de operaciones o similares volátil ++ compuestos volátiles tales operaciones, que no tienen toda atómica.

En resumen, la propia variable de volátil tiene las siguientes características:

  • Visibilidad. La lectura de una variable volátil, siempre capaz de ver (cualquier tema) última escritura esta variable volátil.
  • La atomicidad: la lectura de cualquier sola variable volátil / escritura atómica, pero similar a este tipo de operaciones compuestas no son volátiles ++ atómica.

escritura no volátil - sucede antes del establecimiento de la relación entre la lectura

Mencionado anteriormente es características propias variables volátiles, el programador, el impacto de la volatilidad de rosca visibilidad de la memoria es más importante que las características propias volátiles, pero también necesitan nuestra atención.

A partir de JSR-133, la variable volátil de escritura - lectura comunicación entre hilos puede alcanzar.

De la memoria punto de vista semántico, con el bloqueo del monitor volátiles tienen el mismo efecto: la liberación de escritura no volátil y el monitor tiene la misma memoria semántica; leer el monitor de la adquisición de memoria volátil tiene la misma semántica.

Ver código de ejemplo siguiente las variables volátiles:

class VolatileExample {
    int a = 0;
    volatile boolean flag = false;

    public void writer() {
        a = 1;                   //1
        flag = true;               //2
    }

    public void reader() {
        if (flag) {                //3
            int i =  a;           //4
            ……
        }
    }
}

Después de la ejecución del hilo A es método escritor supuesta (), el hilo B ejecuta el método Reader (). Según sucede antes de que las reglas, un proceso que ocurre antes del establecimiento de la relación se puede dividir en dos categorías:

  1. Las reglas de secuencia de programa, 1 sucede antes de 2; 3 sucede antes de 4.
  2. La regla volátil, 2 ocurre antes de las 3.
  3. La transferencia ocurre antes de las reglas, 1 sucede antes de 4.

La manifestación patrón antes de la relación ocurre de la siguiente manera:

En la figura, los dos nodos de cada eslabón de la flecha, representa un sucede antes de relación. programa flechas negras reglas de secuencia; flechas de color naranja indican regla volátil; flechas azules indican sucede antes de las reglas para asegurar que la composición proporciona.

Un hilo aquí después de escribir una variable volátil, hilos B leyó la misma variable volátil. Un hilo antes de escribir las variables volátiles todas las variables compartidas visibles, hilo B después de leer la misma variable volátil, se convertirá inmediatamente visible para enhebrar B.

volátil de escritura - lectura memoria semántica

la semántica de escritura de memoria volátil son los siguientes:

  • Al escribir una variable volátil, JMM será el hilo correspondiente variables de memoria compartida locales enjuagarse a la memoria principal.

En el ejemplo VolatileExample programa de ejemplo anterior, supongamos que primero ejecuta el hilo Un escritor método (), entonces el hilo B ejecuta el método () Reader, los dos hilo memoria local inicial y una bandera están en un estado inicial. La figura se ejecuta después de la rosca Una escritura volátil, el estado de un compartió esquemática variable:

Como puede observarse, después de escribir la variable de indicador hilo A, los valores de rosca A la memoria local se actualizan dos Una variable compartida se vacía a la memoria principal. En este momento, el valor de la memoria local y la principal variable de la memoria compartida son consistentes.

la semántica de memoria volátil que ahora queda como sigue:

  • Al leer una variable volátil, se está deasserted el hilo correspondiente memoria local JMM. A continuación, el hilo principal leer las variables compartidas de la memoria.

El siguiente es el hilo B lee la misma variable volátil, una vista esquemática de la situación de las variables compartidas:

Como puede observarse, después de leer la variable de la bandera, la memoria local de B ha sido deasserted. En este momento, el hilo B debe leerse de las principales variables de memoria compartida. La lectura de la operación hilo B hará que el valor de B y la memoria local comparten las variables en la memoria principal se convierte también en el mismo.

Si escribimos volátiles y volátiles lectura de estos dos pasos juntos para ver si, después de leer el hilo B lee una variable volátil, escritura hilo A antes de escribir esta variable volátil todos los valores visibles de las variables compartidas se convierten inmediatamente en leer las discusiones B visible.

A continuación, la semántica de memoria de lectura-escritura volátiles y volátiles para ser un resumen:

  • Un hilo escribir una variable volátil, es esencialmente un hilo A emitido (donde modificación de su variable compartida) al siguiente mensaje será leído estas variables volátiles un hilo.
  • Hilo B lee una variable volátil, en esencia, hilo B recibió (antes de escribir esta variable volátil cambios realizados en la variable compartida) mensaje enviado por un hilo antes.
  • Un hilo es una variable volátil para escribir, a continuación, el hilo B lee las variables volátiles, el proceso es esencialmente el hilo A envía un mensaje a través de la memoria principal a la rosca B.

semántica aplicación memoria volátil

Ahora, Echemos un vistazo a cómo JMM memoria semántica para lograr escritura volátil / leer.

Hemos mencionado previamente compilado en el reordenamiento y clasificación desanimados reordenamiento procesador. A fin de lograr la semántica de memoria volátil, JMM limitar los tipos de reordenación de ambos tipos, respectivamente. El siguiente es un compilador desarrollado para la tabla de reglas de reordenación volátil JMM:

Can reordenamiento La segunda operación
La primera operación normal de lectura / escritura volátil de lectura escritura no volátil
normal de lectura / escritura     NO
volátil de lectura NO NO NO
escritura no volátil   NO NO

Por ejemplo, la tercera línea de los últimos medios celulares: el fin del programa, cuando la primera operación es una variables de lectura o de escritura simples, si la segunda operación de escritura tan volátil, el compilador no puede reordenar esta dos operaciones.

A partir de la tabla podemos ver:

  • Cuando la segunda operación es una época volátil de la escritura, no importa lo que es la primera operación que no puede ser reordenada. Esta regla asegura que la operación de escritura volátil antes no se compilará piensa altamente volátil después de haberlo pedido a escribir.
  • Cuando la primera operación es una lectura volátil cuando, no importa lo que es la segunda operación, no puede ser reordenado. Esto asegura que la regla de operación de lectura no volátil será compilada después de haberlo pedido desaniman a leer antes volátil.
  • Cuando la primera operación de escritura es un volátil, inestable segunda operación es una lectura, sin reordenamiento.

A fin de lograr la semántica de memoria volátil, el compilador cuando se inserta el código de bytes de generación en la barrera de memoria secuencia de instrucciones para inhibir un tipo particular de reordenamiento procesador. Para el compilador, encuentre una disposición óptima del número total de inserción para reducir al mínimo las barreras es casi imposible, por lo tanto, JMM tomar una estrategia conservadora. El siguiente se basa en una estrategia de inserción barrera de memoria estrategia JMM conservadores:

  • Cada operación de escritura anterior para insertar una barrera StoreStore volátil.
  • operación de vuelta de escritura se inserta en cada uno de una barrera StoreLoad volátil.
  • Inserción de una barrera LoadLoad volátil después de cada operación de lectura.
  • Inserción de una barrera LoadStore volátil después de cada operación de lectura.

Insertar barrera de memoria por encima de la estrategia es muy conservadora, pero se puede asegurar que cualquier plataforma de procesadores, cualquier programa puede obtener la semántica de memoria volátil correctas.

La siguiente es una estrategia conservadora, la secuencia de comandos esquemática de escritura no volátil generado después de la inserción de las barreras de memoria:

La figura anterior barrera StoreStore puede ser garantizado antes tiene que ser visto en cualquiera del procesador la parte delantera de escritura volátil de toda operación de escritura ordinaria. Esto se debe a la barrera StoreStore protegerá toda la escritura general anterior volcado a la memoria principal antes de la escritura volátil.

Más interesante aquí es escritura volátil detrás de la barrera StoreLoad. El papel de la barrera es evitar volver escritura volátil y puede tener volátil reordenamiento de lectura / escritura. Debido a que el compilador a menudo no puede juzgar con precisión escribió más tarde en una volátil, la necesidad de insertar una barrera StoreLoad (por ejemplo, un método de escritura no volátil inmediatamente después de la vuelta). Con el fin de garantizar para lograr memoria volátil semánticamente correcta, JMM aquí tomó una estrategia conservadora: En cada vuelta de escritura volátil o insertar una barrera StoreLoad delante de cada lectura volátil. Desde la perspectiva de las consideraciones generales de eficiencia, JMM seleccionado detrás de cada insertado en una barrera StoreLoad escritura volátil. Debido a que la escritura no volátil - patrón de uso común se lee la semántica de memoria: un subproceso de escritura para escribir las variables volátiles, múltiples hilos de lectura del lector de la misma variable volátil. Cuando el número de hilos a leer mucho más que un hilo de escritura, seleccione Insertar barrera StoreLoad después de escritura no volátil traerá una considerable mejora de la eficiencia. Desde aquí podemos ver una funcionalidad implementada en JMM: En primer lugar garantizar la exactitud, y luego ir a la búsqueda de la eficiencia.

La siguiente es la estrategia conservadora, las barreras de memoria de instrucciones de lectura volátiles generados después de diagrama de secuencia de inserción:

Figura encima de barrera LoadLoad para desactivar el procesador de leer lo anterior y por debajo de reordenamiento de lectura volátil normal. barrera LoadStore para desactivar el procesador de leer lo anterior y por debajo de reordenamiento de escritura volátil normal.

estrategia anterior volátil y volátil de lectura-escritura barrera de memoria de inserción es muy conservador. En la implementación actual, sin alterar los volátiles de escritura - lectura semántica de memoria, la barrera innecesaria compilador puede omitirse dependiendo de las circunstancias. A continuación se describe un ejemplo específico de un código por:

class VolatileBarrierExample {
    int a;
    volatile int v1 = 1;
    volatile int v2 = 2;

    void readAndWrite() {
        int i = v1;           // 第一个 volatile 读 
        int j = v2;           // 第二个 volatile 读 
        a = i + j;            // 普通写 
        v1 = i + 1;          // 第一个 volatile 写 
        v2 = j * 2;          // 第二个 volatile 写 
    }

    …                    // 其他方法 
}

Para el método readAndWrite (), el compilador genera código de bytes en la optimización se puede realizar de la siguiente manera:

Tenga en cuenta que la última barrera de StoreLoad no puede ser omitida. Porque después de la segunda métodos de escritura no volátil respondieron de inmediato. En este momento, el compilador no puede determinar con exactitud si habrá o no volátil leer ni escribir más adelante, por razones de seguridad, el compilador menudo insertar aquí una barrera StoreLoad.

La optimización anteriormente era para cualquier plataforma de procesador, debido a los diferentes procesadores tienen diferente "tirantez" en el modelo de memoria del procesador, el inserto de barrera de memoria puede seguir memoria del procesador optimizar de acuerdo con el modelo específico. En x86 procesadores, por ejemplo, la imagen de arriba a excepción de la última barrera StoreLoad otra barrera se omitirá.

lectura volátil y de escritura en frente de la estrategia conservadora, en la plataforma de procesadores x86 se pueden optimizar para:

Se mencionó antes, x86 procesadores única escritura - lectura no reordenamiento. X86 no lee - leer, leer - escribir y escribir - operaciones de escritura no reordenamiento, por lo que los procesadores x86 omitirán estas tres operaciones correspondientes al tipo de barrera de memoria. En el 86, JMM solamente la parte de atrás de escritura no volátil insertar una barrera StoreLoad se puede realizar de escritura no volátil correcta - la semántica de memoria de lectura. Esto significa que los procesadores x86, volátil cabeza de lectura-escritura volátil que el costo será mucho más grande (porque la barrera overhead ejecución StoreLoad será relativamente grande).

¿Por JSR-133 para mejorar la semántica de memoria volátil

En el antiguo JSR-133 modelo de memoria de Java antes, aunque no permitió reordenar entre las variables volátiles, pero el viejo modelo de memoria de Java permite el reordenamiento entre volátil y una variable regular. En el modelo de memoria de edad, programa ejemplar VolatileExample puede ser reordenado a la siguiente secuencia se lleva a cabo:

En el antiguo modelo de memoria, entre 1 y 2 cuando no hay dependencias de datos, podrían ser reordenados (similar a 3 y 4) entre 1 y 2. El resultado es: Leer el hilo B ejecuta 4, puede no ser capaz de ver la escritura hilo Una modificación de la ejecución de las variables compartidas 1:00.

Así, en el modelo de memoria de edad, volátil de escritura - lectura no dio a conocer el monitor - Won tiene una semántica de memoria. Con el fin de proporcionar un mecanismo para la comunicación entre un más ligero que los hilos de bloqueo del monitor, JSR-133 mejorado el grupo decidió semántica de memoria volátil: el compilador y el procesador estrictamente limitada a las variables volátiles con variables de reordenamiento normales para asegurar volátil de escritura - lectura y la liberación del monitor - obtener el mismo, tiene la misma semántica de memoria. De alta relación y la estrategia de inserción de barrera de memoria del procesador de intercalación compilado desde el punto de vista, siempre y cuando el reordenamiento entre las variables volátiles y variables comunes puede destruir la semántica de memoria volátil, este reordenamiento serán compilados procesador de intercalación desanimado y barrera de memoria política de inserción prohibido.

Desde volátil de lectura sólo asegura que las variables volátiles individuales / escritura de propiedad atómica, y las características del monitor de bloqueo mutex ejecutada para garantizar la aplicación de la totalidad de la sección crítica atómica de código. Funcionalmente, el bloqueo del monitor es más poderoso que el volátil; en el rendimiento y la escalabilidad de ejecución, la ventaja volátil. Si los lectores desean reemplazar el monitor con bloqueo de programa volátil, asegúrese de tener cuidado.

 

Publicados 136 artículos originales · ganado elogios 6 · vistas 1487

Supongo que te gusta

Origin blog.csdn.net/weixin_42073629/article/details/104741609
Recomendado
Clasificación