validos - Ejemplo más simple y comprensible de palabra clave volátil en Java




para que son las palabras reservadas en java (8)

Idealmente, si keepRunning no era volátil, el hilo debería seguir ejecutándose indefinidamente. Pero, se detiene después de unos segundos.

Si está ejecutando en un solo procesador o si su sistema está muy ocupado, el sistema operativo puede estar intercambiando los hilos que causa algunos niveles de invalidación de caché. Como han mencionado otros, no tener un elemento volatile no significa que la memoria no se compartirá, pero la JVM intenta no sincronizar la memoria si puede por motivos de rendimiento, por lo que la memoria puede no actualizarse.

Otra cosa a tener en cuenta es que System.out.println(...) se sincroniza porque el PrintStream subyacente realiza la sincronización para detener la superposición de resultados. Por lo tanto, obtiene sincronización de memoria "gratis" en el hilo principal. Sin embargo, esto todavía no explica por qué el ciclo de lectura ve las actualizaciones.

Ya sea que las println(...) estén dentro o fuera, su programa gira para mí bajo Java6 en una MacBook Pro con Intel i7.

¿Alguien puede explicar volátil con el ejemplo? No con la teoría de JLS.

Creo que tu ejemplo es bueno. No estoy seguro de por qué no funciona con todas las sentencias System.out.println(...) eliminadas. Esto funciona para mi.

¿Es un sustituto volátil para la sincronización? ¿Logra la atomicidad?

En términos de sincronización de memoria, volatile lanza las mismas barreras de memoria que un bloque synchronized excepto que la barrera volatile es unidireccional versus bidireccional. volatile lecturas volatile arrojan una barrera de carga mientras que las escrituras arrojan una barrera de la tienda. Un bloque synchronized es una barrera bidireccional.

En términos de atomicity , sin embargo, la respuesta es "depende". Si está leyendo o escribiendo un valor de un campo, entonces volatile proporciona la atomicidad adecuada. Sin embargo, el incremento de un campo volatile adolece de la limitación de que ++ es en realidad 3 operaciones: leer, incrementar, escribir. En ese caso o casos más complejos de mutex, un bloqueo synchronized completo está en orden.

Estoy leyendo sobre palabras clave volátiles en Java y entiendo completamente la parte de la teoría.

Pero, lo que estoy buscando es un buen ejemplo de caso, que muestra lo que sucedería si la variable no fuera volátil y si lo fuera.

El siguiente fragmento de código no funciona como se esperaba ( de aioobe )

class Test extends Thread {

    boolean keepRunning = true;

    public void run() {
        while (keepRunning) {
        }

        System.out.println("Thread terminated.");
    }

    public static void main(String[] args) throws InterruptedException {
        Test t = new Test();
        t.start();
        Thread.sleep(1000);
        t.keepRunning = false;
        System.out.println("keepRunning set to false.");
    }
}

Idealmente, si keepRunning no era volátil, el hilo debería seguir ejecutándose indefinidamente. Pero, se detiene después de unos segundos.

Tengo dos preguntas básicas:

  • ¿Alguien puede explicar volátil con el ejemplo? No con la teoría de JLS.
  • ¿Es un sustituto volátil para la sincronización? ¿Logra la atomicidad?

Cuando una variable es volatile , garantiza que no se almacenará en caché y que los diferentes subprocesos verán el valor actualizado. Sin embargo, no marcarlo como volatile no garantiza la oposición. volatile fue una de esas cosas que se rompieron en la JVM durante mucho tiempo y aún no siempre se entienden bien.


He modificado tu ejemplo ligeramente. Ahora usa el ejemplo con keepRunning como miembro volátil y no volátil:

class TestVolatile extends Thread{
    //volatile
    boolean keepRunning = true;

    public void run() {
        long count=0;
        while (keepRunning) {
            count++;
        }

        System.out.println("Thread terminated." + count);
    }

    public static void main(String[] args) throws InterruptedException {
        TestVolatile t = new TestVolatile();
        t.start();
        Thread.sleep(1000);
        System.out.println("after sleeping in main");
        t.keepRunning = false;
        t.join();
        System.out.println("keepRunning set to " + t.keepRunning);
    }
}

Los objetos que se declaran como volátiles generalmente se utilizan para comunicar información de estado entre subprocesos, para garantizar que las cachés de CPU se actualicen, es decir, se mantengan sincronizadas, en presencia de campos volátiles, una instrucción de CPU, una barrera de memoria, a menudo denominada membar o valla, se emite para actualizar las memorias caché de la CPU con un cambio en el valor de un campo volátil.

El modificador volátil le dice al compilador que la variable modificada por el volátil puede cambiarse inesperadamente por otras partes de su programa.

La variable volátil se debe usar solo en el contexto de subprocesos. mira el ejemplo here


Volátil -> Garantiza visibilidad y NO atomicidad

Sincronización (Bloqueo) -> Garantiza la visibilidad y la atomicidad (si se realiza correctamente)

Volátil no es un sustituto de la sincronización

Use la palabra volátil solo cuando esté actualizando la referencia y no realice otras operaciones en ella.

Ejemplo:

volatile int i = 0;

public void incrementI(){
   i++;
}

no será seguro para subprocesos sin el uso de sincronización o AtomicInteger ya que el incremento es una operación compuesta.

¿Por qué el programa no se ejecuta indefinidamente?

Bueno, eso depende de varias circunstancias. En la mayoría de los casos, JVM es lo suficientemente inteligente como para eliminar los contenidos.

El uso correcto de volátiles discute varios usos posibles de volátiles. Usar el volátil correctamente es complicado, yo diría "En caso de duda, déjalo fuera", utiliza el bloque sincronizado.

También:

el bloque sincronizado se puede usar en lugar de volátil pero el inverso no es verdadero .


si declara una variable como volátil, no se almacenará en la memoria caché local. Cada vez que el hilo está actualizando los valores, se actualiza a la memoria principal. Por lo tanto, otros subprocesos pueden acceder al valor actualizado.


volatile no va a crear necesariamente cambios gigantescos, según la JVM y el compilador. Sin embargo, para muchos casos (de borde), puede ser la diferencia entre la optimización que causa que los cambios de una variable no se noten en lugar de que se escriban correctamente.

Básicamente, un optimizador puede elegir colocar variables no volátiles en los registros o en la pila. Si otro subproceso los cambia en el montón o en las primitivas de las clases, el otro subproceso seguirá buscándolo en la pila, y estará obsoleto.

volatile asegura que tales optimizaciones no suceden y todas las lecturas y escrituras son directamente al montón u otro lugar donde todos los hilos lo verán.


¿Qué es palabra clave volátil?

palabra clave volátil evita el caching of variables .

Considere el código, primero sin palabra clave volátil

class MyThread extends Thread {
    private boolean running = true;   //non-volatile keyword

    public void run() {
        while (running) {
            System.out.println("hello");
        }
    }

    public void shutdown() {
        running = false;
    }
}

public class Main {

    public static void main(String[] args) {
        MyThread obj = new MyThread();
        obj.start();

        Scanner input = new Scanner(System.in);
        input.nextLine(); 
        obj.shutdown();   
    }    
}

Idealmente , este programa debería print hello hasta que se presione la RETURN key . Pero en some machines puede suceder que la ejecución variable esté en cached y no se puede cambiar su valor del método shutdown (), lo que da como resultado infinite impresión infinite de texto hola.

Por lo tanto, al usar palabra clave volátil, se guaranteed que su variable no se almacenará en caché, es decir, se run fine en all machines .

private volatile boolean running = true;  //volatile keyword

Por lo tanto, usar palabras clave volátiles es una safer programming practice good y safer programming practice .





volatile