Pregunta

Hoy en el trabajo, me encontré con el volatile palabra clave de Java.No están muy familiarizados con él, me encontré con esta explicación:

Java teoría y la práctica:La gestión de la volatilidad de los

Dado el detalle de que ese artículo se explica la palabra clave en cuestión, ¿alguna vez uso o podría usted nunca ha visto un caso en el que usted podría utilizar esta palabra clave en la manera correcta?

¿Fue útil?

Solución

volatile tiene una semántica para la memoria de la visibilidad.Básicamente, el valor de un volatile el campo se convierte en visible para todos los lectores (otros hilos en particular) después de una operación de escritura completa en él.Sin volatile, los lectores pueden ver algunos de los no-valor actualizado.

Para responder a su pregunta:Sí, yo uso un volatile variable para controlar si el código sigue un bucle.El bucle de prueba de la volatile valor y si es que sigue true.La condición puede ser configurado para false llamando a un "stop" método.El bucle se ve false y termina cuando se evalúa el valor después de la parada método finalice la ejecución.

El libro "Java Concurrencia en la Práctica"que yo recomiendo, da una buena explicación de volatile.Este libro está escrito por la misma persona que escribió el IBM artículo al que se hace referencia en la pregunta (de hecho, habla de su libro en la parte inferior de este artículo).Mi uso de volatile es lo que su artículo se llama el "patrón 1 indicador de estado."

Si usted desea aprender más acerca de cómo volatile funciona bajo el capó, leer en el modelo de memoria de Java.Si quieres ir más allá de ese nivel, retirar una buena arquitectura de computadores libro como Hennessy Y Patterson y leer acerca de la coherencia de caché y caché de consistencia.

Otros consejos

"... el modificador volatile garantiza que cualquier hilo que se lee de un campo a ver el más recientemente escrita de valor." - Josh Bloch

Si usted está pensando en usar volatile, leer en el paquete java.util.concurrent que se ocupa de la atómica de comportamiento.

La Wikipedia en un post Patrón Singleton muestra volátil en uso.

Punto importante acerca de volatile:

  1. La sincronización en Java es posible mediante el uso de palabras clave de Java synchronized y volatile y cerraduras.
  2. En Java, que no pueden tener synchronized variable.El uso de synchronized palabra clave con una variable es ilegal y resultará en un error de compilación.En lugar de utilizar el synchronized variable en Java, puede utilizar el java volatile variable, la cual instruirá JVM hilos para leer el valor de volatile variable de la memoria principal y no almacenar en caché localmente.
  3. Si una variable no es compartida entre varios subprocesos entonces no hay necesidad de usar el volatile la palabra clave.

fuente

Ejemplo de uso de volatile:

public class Singleton {
    private static volatile Singleton _instance; // volatile variable
    public static Singleton getInstance() {
        if (_instance == null) {
            synchronized (Singleton.class) {
                if (_instance == null)
                    _instance = new Singleton();
            }
        }
        return _instance;
    }
}

Estamos creando instancia perezosamente en el momento de la primera solicitud que se viene.

Si no hacemos el _instance variable volatile a continuación, el Hilo que es la creación de la instancia de Singleton no es capaz de comunicarse con el otro hilo.Así que si Un Hilo es la creación de instancia Singleton y sólo después de la creación, la CPU corrompe etc, todos los otros hilos no será capaz de ver el valor de _instance como no nulo y que se cree que todavía está asignada null.

¿Por qué sucede esto?Porque el lector de hilos no están haciendo ningún bloqueo y hasta el escritor hilo que sale de un bloque sincronizado, la memoria no se sincronizan y el valor de _instance no se actualizará en la memoria principal.Con la palabra clave Volatile en Java, esto es manejado por Java en sí y de estas actualizaciones serán visibles por todos lector de hilos.

Conclusión: volatile palabras clave también se utiliza para comunicar el contenido de la memoria entre los hilos.

Ejemplo de uso de sin volátiles:

public class Singleton{    
    private static Singleton _instance;   //without volatile variable
    public static Singleton getInstance(){   
          if(_instance == null){  
              synchronized(Singleton.class){  
               if(_instance == null) _instance = new Singleton(); 
      } 
     }   
    return _instance;  
    }

El código anterior no es thread-safe.Aunque se comprueba el valor de la instancia, una vez más dentro del bloque sincronizado (por razones de rendimiento), el compilador JIT se puede cambiar el código de bytes de una manera que la referencia a la instancia que se establece antes de que el constructor ha terminado su ejecución.Esto significa que el método getInstance() devuelve un objeto que no puede haber sido inicializado por completo.Para hacer que el código thread-safe, la palabra clave volátil puede ser utilizado desde Java 5 para la variable de instancia.Las Variables que están marcados como la volatilidad de obtener sólo visible para otros hilos una vez que el constructor del objeto ha terminado su ejecución por completo.
Fuente

enter image description here

volatile uso en Java:

El fail-rápido son los iteradores normalmente implementado el uso de un volatile contador en la lista de objetos.

  • Cuando la lista se actualiza, se incrementa el contador.
  • Cuando un Iterator se crea, el valor actual del contador está incrustado en el Iterator objeto.
  • Cuando un Iterator se realiza la operación, el método compara los dos valores de contador y lanza un ConcurrentModificationException si son diferentes.

La aplicación de fail-safe iteradores es normalmente de peso ligero.Ellos normalmente se basan en las propiedades de la lista específica de la implementación de estructuras de datos.No hay ningún patrón general.

volátil es muy útil para detener los hilos.

No es que usted debe escribir su propio hilos, Java 1.6 tiene un buen montón de grupos de hilos.Pero si estás seguro de que necesitas un hilo, usted necesita saber cómo detener.

El patrón de uso de hilos es:

public class Foo extends Thread {
  private volatile boolean close = false;
  public void run() {
    while(!close) {
      // do work
    }
  }
  public void close() {
    close = true;
    // interrupt here if needed
  }
}

Observe cómo que no hay necesidad de sincronización

Un ejemplo común para el uso de volatile es el uso de un volatile boolean variable como un indicador para terminar un hilo.Si usted ha comenzado un hilo, y usted quiere ser capaz de interrumpir de manera segura desde un subproceso diferente, usted puede tener el hilo comprobar periódicamente una bandera.Para detenerlo, al flag a true.Haciendo la bandera volatile, puede asegurarse de que el hilo que es la comprobación de que se vea que se ha fijado la próxima vez que se comprueba sin tener que usar synchronized el bloque.

Una variable declarada con volatile palabra clave, tiene dos principales cualidades que la hacen especial.

  1. Si tenemos una variable volátil, no puede ser almacenado en la caché del equipo(microprocesador) memoria caché por cualquier hilo.Acceso ocurrido siempre desde la memoria principal.

  2. Si hay un operación de escritura pasando a la volatilidad de la variable, y de repente un operación de lectura se solicita, se garantiza que la operación de escritura será terminado antes de la operación de lectura.

Dos cualidades mencionadas deducir que

  • Todos los hilos de la lectura de una variable volátil definitivamente leer el valor más reciente.Porque no hay ningún valor almacenado en caché puede contaminar.Y también la lectura petición será concedida sólo después de la finalización de la operación de escritura.

Y por otro lado,

  • Si nos investigar la #2 que he mencionado, podemos ver que volatile palabra clave es una forma ideal para mantener una variable compartida que ha 'n' número de leer hilos y sólo una escritura hilo para acceder a ella.Una vez se añade el volatile palabra clave es hecho.No cualquier otros gastos generales acerca de la seguridad de los subprocesos.

Conversly,

Nosotros no se puede hacer uso de volatile palabras clave exclusivamente, para satisfacer a una variable compartida que ha más que una escritura hilos de acceder a él.

Sí, la volatilidad debe ser utilizado cuando quieras una variable mutable para ser accedida por múltiples hilos.No es muy común el caso de uso porque normalmente se necesita realizar más de una operación atómica (por ejemplo,compruebe la variable de estado antes de modificarlo), en cuyo caso usted podría usar un bloque sincronizado en su lugar.

Nadie ha mencionado el tratamiento de la operación de lectura y escritura para el largo y el doble de tipo de variable.Lee y escribe son operaciones atómicas para hacer referencia a las variables y para la mayoría de las variables primitivas, excepto las de largo y el doble de los tipos de variables, que debe utilizar la palabra clave volatile a ser operaciones atómicas. @link

En mi opinión, dos de los más importantes escenarios de otros de detener el hilo en el que la palabra clave volatile se utilizan son:

  1. Doble comprobación de mecanismo de bloqueo.Se utiliza a menudo en el diseño Singleton patrón.En este el objeto singleton necesita ser declarada volátiles.
  2. Espurias Despertadores.Hilo a veces puede despertar de esperar la llamada, incluso si no notificar a la llamada haya sido emitido.Este comportamiento se denomina supurious el despertador.Esto puede ser contrarrestado mediante el uso de una variable condicional(indicador booleano).Poner el wait() llamada en un bucle while, mientras la bandera es cierto.Así que si el hilo se despierta de esperar debido a alguna de las otras razones que notificar/notifyall, a continuación, se encuentra la bandera es cierto y, por tanto, llama a esperar de nuevo.Antes de llamar a notificar a establecer esta bandera de la verdad.En este caso el indicador booleano es declarada como la volatilidad de los.

Usted tendrá que utilizar 'volátil' palabra clave', o 'sincronizados', y cualquier otro control de concurrencia herramientas y técnicas que usted puede tener a su disposición si usted es el desarrollo de una aplicación multiproceso.Ejemplo de este tipo de aplicación es el de las aplicaciones de escritorio.

Si está desarrollando una aplicación que podría ser implementado para servidor de aplicaciones (Tomcat, JBoss as, Glassfish, etc) usted no tiene que manejar la concurrencia de control de ti mismo como ya abordados por el servidor de aplicaciones.De hecho, si recordaba correctamente el estándar Java EE prohibir el uso de cualquier control de concurrencia en servlets y Ejb, ya que es parte de la "infraestructura" de la capa, que se supone que deberían ser liberados de su manipulación.Sólo se hace el control de concurrencia en dicha aplicación, si usted está implementando objetos singleton.Esto incluso ya se han abordado si usted teje sus componentes mediante frameworkd como la Primavera.

Así, en la mayoría de los casos de desarrollo de Java, donde la aplicación es una aplicación web y el uso de Coi marco como la Primavera o el EJB, no necesita el uso de "volátil".

volatile sólo se garantiza que todos los hilos, incluso, se están incrementando.Por ejemplo:un contador ve la misma cara de la variable al mismo tiempo.No se utiliza en lugar de sincronizada o atómica o de otras cosas, es completamente hace que la lee sincronizado.Por favor, no comparar con otras palabras clave de java.Como se muestra en el ejemplo a continuación volátiles variable y operaciones atómicas que fracasar o tener éxito a la vez.

package io.netty.example.telnet;

import java.util.ArrayList;
import java.util.List;

public class Main {

    public static volatile  int a = 0;
    public static void main(String args[]) throws InterruptedException{

        List<Thread> list = new  ArrayList<Thread>();
        for(int i = 0 ; i<11 ;i++){
            list.add(new Pojo());
        }

        for (Thread thread : list) {
            thread.start();
        }

        Thread.sleep(20000);
        System.out.println(a);
    }
}
class Pojo extends Thread{
    int a = 10001;
    public void run() {
        while(a-->0){
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            Main.a++;
            System.out.println("a = "+Main.a);
        }
    }
}

Incluso poner volátiles o no resultados serán siempre diferentes.Pero si usted utiliza AtomicInteger como a continuación los resultados serán siempre los mismos.Este es el mismo con sincronizan también.

    package io.netty.example.telnet;

    import java.util.ArrayList;
    import java.util.List;
    import java.util.concurrent.atomic.AtomicInteger;

    public class Main {

        public static volatile  AtomicInteger a = new AtomicInteger(0);
        public static void main(String args[]) throws InterruptedException{

            List<Thread> list = new  ArrayList<Thread>();
            for(int i = 0 ; i<11 ;i++){
                list.add(new Pojo());
            }

            for (Thread thread : list) {
                thread.start();
            }

            Thread.sleep(20000);
            System.out.println(a.get());

        }
    }
    class Pojo extends Thread{
        int a = 10001;
        public void run() {
            while(a-->0){
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                Main.a.incrementAndGet();
                System.out.println("a = "+Main.a);
            }
        }
    }

Sí, yo lo uso bastante -, puede ser muy útil para multi-roscado código.El artículo que usted señala es una buena.A pesar de que hay dos cosas importantes a tener en cuenta:

  1. Sólo debe utilizar volátil si entiendo completamente lo que hace y cómo se diferencia a sincronizados.En muchas situaciones volátiles aparece, en la superficie, para ser más simples, rendimiento excelente alternativa para sincronizado, cuando a menudo una mejor la comprensión de la volatilidad de los haría claro que sincronizan es la única opción que podría funcionar.
  2. volátil en realidad no trabajo en un muchos de los otros Jvm, aunque sincronizado hace.Recuerdo haber visto un documento que hace referencia a los diferentes niveles de apoyo en diferentes Jvm, pero lamentablemente no lo encuentro ahora.Sin duda mirar en lo que si usted está utilizando Java pre 1.5 o si usted no tiene control sobre la Jvm que el programa se ejecuta.

Absolutamente, sí.(Y no sólo en Java, pero también en C#.) Hay veces cuando usted necesita para obtener o establecer un valor que está garantizado para ser una operación atómica en su plataforma, un int o booleano, por ejemplo, pero que no requieren la sobrecarga de hilo de bloqueo.La palabra clave volatile le permite asegurarse de que cuando usted lea el valor que usted obtenga el actual valor y no un valor almacenado en caché que se acaba de hacer obsoleto por escribir en otro hilo.

Cada hilo de acceder a la volatilidad del campo de lectura de su valor actual antes de continuar, en lugar de (potencialmente) el uso de un valor almacenado en caché.

Sólo miembro de la variable puede ser volátil o transitoria.

Hay dos usos diferentes de la palabra clave volatile.

  1. Evita la JVM a partir de la lectura de los valores de registro (asumir como caché), y las fuerzas de su valor para ser leído de la memoria.
  2. Reduce el riesgo de memoria en errores de consistencia.

Evita la JVM a partir de la lectura de los valores en el registro, y las fuerzas de su valor de la lectura de la memoria.

Un indicador ocupado se utiliza para evitar que un hilo de continuar mientras el dispositivo está ocupado y la bandera no está protegido por una cerradura:

while (busy) {
    /* do something else */
}

La prueba de hilo continuará cuando otro hilo, se apaga el indicador ocupado:

busy = 0;

Sin embargo, desde ocupado se accede con frecuencia en las pruebas de hilo, la JVM puede optimizar la prueba colocando el valor de ocupados en un registro, a continuación, probar el contenido de dicho registro, sin leer el valor de ocupados en la memoria antes de cada prueba.La prueba de hilo nunca volvería a ver a ocupado el cambio y el otro hilo sólo cambiar el valor de ocupados en la memoria, lo que resulta en un punto muerto.Declarar la indicador ocupado como la volatilidad de las fuerzas de su valor para ser leído antes de cada prueba.

Reduce el riesgo de la memoria de errores de coherencia.

El uso de variables volátiles reduce el riesgo de memoria de errores de coherencia, debido a que cualquier escritura a una variable volátil establece un "ocurre antes de" relación con las lecturas posteriores de la misma variable.Esto significa que los cambios en una variable volátil siempre son visibles para otros hilos.

La técnica de la lectura, la escritura sin la memoria de errores de coherencia se llama atómica acción.

Una acción atómica es uno de los que efectivamente sucede todo a la vez.Atómico de la acción no puede parar en el medio:tampoco pasa completamente, o no ocurrir en absoluto.No efectos secundarios de un átomo de acción son visibles hasta que finalice la acción.

A continuación son acciones que usted puede especificar que son atómicas:

  • Lee y escribe son atómicas para hacer referencia a las variables y para la mayoría de variables primitivas (todos los tipos, excepto long y double).
  • Lee y escribe son atómicas para todas las variables declaradas volátiles (incluidos los largos y doble variables).

Saludos!

Volátiles Variables de peso ligero de la sincronización.Cuando la visibilidad de los datos más recientes entre todos los hilos, es requisito y la atomicidad puede estar en peligro , en tales situaciones Volátiles Variables debe ser preferido.Lectura de los volátiles de las variables siempre devolver la mayoría de escritura reciente realizado por cualquier hilo, ya que no son ni caché en los registros ni en escondites donde otros procesadores no pueden ver.Volátil es Libre de Bloqueo.Yo uso volátil, cuando el escenario cumple con los criterios mencionados anteriormente.

Volátiles no siguiente.

1> Leer y escribir de la volatilidad de las variables por diferentes hilos son siempre de la memoria, no en el hilo de la propia caché de cpu o registro.Por lo que cada hilo siempre trata con el valor más reciente.2> Cuando 2 hilos diferentes de trabajo con la misma instancia o variables estáticas en montón, uno puede ver otros actos fuera de orden.Ver a jeremy manson blog sobre esto.Sin embargo, la volatilidad ayuda aquí.

Siguiente plenamente la ejecución de código muestra cómo un número de subprocesos pueden ejecutar en orden predefinido y salidas de impresión sin utilizar la palabra clave synchronized.

thread 0 prints 0
thread 1 prints 1
thread 2 prints 2
thread 3 prints 3
thread 0 prints 0
thread 1 prints 1
thread 2 prints 2
thread 3 prints 3
thread 0 prints 0
thread 1 prints 1
thread 2 prints 2
thread 3 prints 3

Para lograr esto, podemos usar el siguiente pleno derecho, la ejecución de código.

public class Solution {
    static volatile int counter = 0;
    static int print = 0;
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Thread[] ths = new Thread[4];
        for (int i = 0; i < ths.length; i++) {
            ths[i] = new Thread(new MyRunnable(i, ths.length));
            ths[i].start();
        }
    }
    static class MyRunnable implements Runnable {
        final int thID;
        final int total;
        public MyRunnable(int id, int total) {
            thID = id;
            this.total = total;
        }
        @Override
        public void run() {
            // TODO Auto-generated method stub
            while (true) {
                if (thID == counter) {
                    System.out.println("thread " + thID + " prints " + print);
                    print++;
                    if (print == total)
                        print = 0;
                    counter++;
                    if (counter == total)
                        counter = 0;
                } else {
                    try {
                        Thread.sleep(30);
                    } catch (InterruptedException e) {
                        // log it
                    }
                }
            }
        }
    }
}

El siguiente enlace de github tiene un readme, que da una explicación correcta.https://github.com/sankar4git/volatile_thread_ordering

A partir de la documentación de oracle página, la necesidad de volátiles variable surge para corregir memoria problemas de coherencia:

El uso de variables volátiles reduce el riesgo de la memoria de errores de coherencia, porque cualquiera que escribir en una variable volátil establece un pasa-antes de que la relación con las lecturas posteriores de la misma variable.

Esto significa que los cambios a un volatile variable siempre son visibles para otros hilos.Esto también significa que cuando un hilo se lee una variable volátil, se ve no sólo el último cambio a la volatile, pero también los efectos secundarios del código que desembocaron en el cambio.

Como se explica en Peter Parker la respuesta, en ausencia de volatile modificador de cada pila del subproceso puede tener su propia copia de la variable.Haciendo la variable como volatile, de la memoria , la consistencia de los problemas se han solucionado.

Eche un vistazo a jenkov tutorial de la página para una mejor comprensión.

Tener una mirada en relación SE pregunta para más detalles sobre los volátiles y uso casos de uso de volátiles:

Diferencia entre volátil y sincronizados en Java

Una práctica de casos de uso:

Tienes muchos hilos, que necesita para imprimir hora actual en un formato determinado, por ejemplo : java.text.SimpleDateFormat("HH-mm-ss").Yon puede tener una clase, que convierte la hora actual en SimpleDateFormat y actualizado de la variable para cada uno de segunda.Todos los demás subprocesos puede simplemente utilizar este volátiles variable a imprimir actual del tiempo en los archivos de registro.

Un Volátiles variable se modifica de forma asincrónica mediante la ejecución simultánea de los hilos en una aplicación Java.No está permitido tener una copia local de una variable que es diferente del valor que se celebra actualmente en la "principal" de la memoria.Efectivamente, una variable declarada volátiles deben tener sus datos sincronizados en todos los hilos, de modo que siempre que el acceso o la actualización de la variable en cualquier hilo, todos los demás subprocesos ver de inmediato el mismo valor.Por supuesto, es probable que los volátiles de las variables tienen un mayor acceso y actualización de la sobrecarga de "llanura" variables, desde la razón que los hilos pueden tener su propia copia de los datos para una mejor eficiencia.

Cuando un campo es declarado volátiles, la ejecución y el compilador se ponen sobre aviso de que esta variable es compartido y que las operaciones no debe ser reordenados con otras operaciones de memoria.Volátiles variables no se almacenan en los registros o en escondites donde están ocultos de otros procesadores, por lo que una lectura de la volatilidad de la variable devuelve siempre el más reciente escribir por cualquier hilo.

para referencia, consulte este http://techno-terminal.blogspot.in/2015/11/what-are-volatile-variables.html

La volátil clave cuando se utiliza con una variable, se asegurará de que los hilos de la lectura de esta variable va a ver el mismo valor .Ahora, si usted tiene múltiples hilos de la lectura y la escritura a una variable, haciendo que la variable volátil no será suficiente y los datos serán dañados .Imagen hilos han leído el mismo valor, pero cada uno ha hecho algunos chages (es decir que se incrementa un contador) , al escribir de nuevo a la memoria, la integridad de los datos es violado .Es por eso que es necesario hacer la varible sincronizado (diferentes formas son posibles)

Si los cambios se hacen por 1 hilo y que los demás necesitan, para leer este valor, la volatilidad será adecuado.

Me gusta Jenkov la explicación:

El Java volátiles la palabra clave se utiliza para marcar una variable de Java como "ser almacenados en la memoria principal".Más precisamente, esto significa que, cada lectura de una variable volátil va a leer desde la memoria principal del ordenador, y no desde la caché de CPU, y que cada escritura a la volatilidad de la variable será escrito a la memoria principal, y no sólo a la caché de CPU.

En realidad, a partir de Java 5 la palabra clave volatile garantiza más que eso volátiles variables se escriben y se leen de la memoria principal.

Es extendida la visibilidad de la garantía de los llamados sucede-antes de garantía.

Consideraciones de rendimiento de la volatilidad de los

La lectura y la escritura de la volatilidad de las variables provoca que la variable puede leer o escribir en la memoria principal.Leer y escribir en la memoria principal, es más caro que el acceso a la caché de CPU.El acceso volátiles variables también prevenir la instrucción de la reordenación que es normal en la mejora de rendimiento de la técnica.Por lo tanto, sólo se debe utilizar volátiles variables cuando usted realmente necesita para hacer cumplir la visibilidad de las variables.

volátiles variable se utiliza básicamente para la actualización instantánea (color) en compartida principal de la línea de caché una vez actualizado, de modo que los cambios se refleja a todos los subprocesos de trabajo de inmediato.

A continuación es un código muy simple para demostrar el requisito de volatile para la variable que se utiliza para el control de la ejecución del Hilo de otro hilo (este es un escenario donde volatile se requiere).

// Code to prove importance of 'volatile' when state of one thread is being mutated from another thread.
// Try running this class with and without 'volatile' for 'state' property of Task class.
public class VolatileTest {
    public static void main(String[] a) throws Exception {
        Task task = new Task();
        new Thread(task).start();

        Thread.sleep(500);
        long stoppedOn = System.nanoTime();

        task.stop(); // -----> do this to stop the thread

        System.out.println("Stopping on: " + stoppedOn);
    }
}

class Task implements Runnable {
    // Try running with and without 'volatile' here
    private volatile boolean state = true;
    private int i = 0;

    public void stop() {
        state = false;
    } 

    @Override
    public void run() {
        while(state) {
            i++;
        }
        System.out.println(i + "> Stopped on: " + System.nanoTime());
    }
}

Cuando volatile no se usa: nunca vas a ver"Se detuvo en:xxx'mensaje incluso después de 'Parando en:xxx', y el programa continúa su ejecución.

Stopping on: 1895303906650500

Cuando volatile usa: verás el 'Se detuvo en:xxx"inmediatamente.

Stopping on: 1895285647980000
324565439> Stopped on: 1895285648087300

Demo: https://repl.it/repls/SilverAgonizingObjectcode

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top