usar jcolorchooser ejemplo definicion codigo java multithreading concurrency keyword volatile

jcolorchooser - ¿Alguna vez usas la palabra clave volátil en Java?



jlabel html (21)

Absolutamente sí. (Y no solo en Java, sino también en C #). Hay ocasiones en las que necesita obtener o establecer un valor que garantice ser una operación atómica en su plataforma determinada, por ejemplo, int o boolean, pero no requiere La sobrecarga de bloqueo de hilo. La palabra clave volátil le permite asegurarse de que cuando lea el valor obtenga el valor actual y no un valor almacenado en caché que se haya quedado obsoleto por una escritura en otro subproceso.

En el trabajo de hoy, me encontré con la palabra clave volatile en Java. No estando muy familiarizado con esto, encontré esta explicación:

Teoría y práctica de Java: Gestionando la volatilidad.

Dado el detalle en el que ese artículo explica la palabra clave en cuestión, ¿alguna vez la usa o podría ver un caso en el que podría usar esta palabra clave de la manera correcta?


Cada hilo que accede a un campo volátil leerá su valor actual antes de continuar, en lugar de (potencialmente) usar un valor almacenado en caché.

Solo la variable miembro puede ser volátil o transitoria.


Desde la page documentación de page , surge la necesidad de una variable volátil para solucionar los problemas de consistencia de la memoria:

El uso de variables volátiles reduce el riesgo de errores de consistencia de la memoria, porque cualquier escritura en una variable volátil establece una relación de suceso antes con lecturas posteriores de la misma variable.

Esto significa que los cambios en una variable volatile siempre son visibles para otros subprocesos. También significa que cuando un hilo lee una variable volátil, no solo ve el último cambio en la volatile , sino también los efectos secundarios del código que provocó el cambio.

Como se explicó en la respuesta de Peter Parker , en ausencia de un modificador volatile , la pila de cada hilo puede tener su propia copia de la variable. Al hacer que la variable sea volatile , se han solucionado los problemas de consistencia de la memoria.

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

Eche un vistazo a la pregunta de SE relacionada para obtener más detalles sobre los casos de uso y volatilidad para usar volatile:

Diferencia entre lo volátil y lo sincronizado en Java.

Un caso de uso práctico:

Tiene muchos hilos, que necesitan imprimir la hora actual en un formato particular, por ejemplo: java.text.SimpleDateFormat("HH-mm-ss") . Yon puede tener una clase, que convierte la hora actual en SimpleDateFormat y actualiza la variable por cada segundo. Todos los demás subprocesos pueden simplemente usar esta variable volátil para imprimir la hora actual en los archivos de registro.


En mi opinión, dos escenarios importantes distintos a la detención del subproceso en el que se utiliza la palabra clave volátil son

  1. Mecanismo de bloqueo de doble control . Se utiliza a menudo en el patrón de diseño Singleton. En este caso, el singleton object needs to be declared volatile .
  2. Despertadores espurios . El hilo a veces puede despertarse de una llamada en espera incluso si no se ha emitido una llamada de notificación. Este comportamiento se llama activación supurativa. Esto se puede contrarrestar usando una variable condicional (indicador booleano). Coloque la llamada en espera () en un bucle while siempre que la marca sea verdadera. Por lo tanto, si el subproceso se despierta de una llamada en espera debido a cualquier otro motivo que no sea notificar / notificar, entonces se encuentra el indicador que sigue siendo verdadero y, por lo tanto, las llamadas vuelven a esperar. Antes de llamar a notificar, establezca este indicador en verdadero. En este caso, la boolean flag is declared as volatile .

Hay dos usos diferentes de la palabra clave volátil.

  1. Evita que la JVM lea los valores del registro (se asume como caché) y obliga a que su valor se lea de la memoria.
  2. Reduce el riesgo de errores de falta de coherencia de memoria.

Evita que la JVM lea los valores en el registro y obliga a que su valor se lea de la memoria.

Se usa un indicador de ocupado para evitar que un hilo continúe mientras el dispositivo está ocupado y el indicador no está protegido por un bloqueo:

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

El hilo de prueba continuará cuando otro hilo desactive el indicador de ocupado :

busy = 0;

Sin embargo, dado que se accede a busy en el subproceso de prueba, la JVM puede optimizar la prueba al colocar el valor de busy en un registro, luego probar el contenido del registro sin leer el valor de busy en la memoria antes de cada prueba. El subproceso de prueba nunca vería un cambio de ocupado y el otro subproceso solo cambiaría el valor de ocupado en la memoria, lo que provocaría un punto muerto. Declarar el indicador de ocupado como volátil obliga a leer su valor antes de cada prueba.

Reduce el riesgo de errores de consistencia de memoria.

El uso de variables volátiles reduce el riesgo de errores de consistencia de la memoria , ya que cualquier escritura en una variable volátil establece una relación de "sucede antes de" con lecturas subsiguientes de esa misma variable. Esto significa que los cambios en una variable volátil siempre son visibles para otros subprocesos.

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

Una acción atómica es aquella que efectivamente sucede todo al mismo tiempo. Una acción atómica no puede detenerse en el medio: o bien sucede completamente o no sucede en absoluto. Ningún efecto secundario de una acción atómica es visible hasta que la acción se completa.

A continuación se muestran las acciones que puede especificar que son atómicas:

  • Las lecturas y escrituras son atómicas para las variables de referencia y para la mayoría de las variables primitivas (todos los tipos excepto largos y dobles).
  • Las lecturas y escrituras son atómicas para todas las variables declaradas volátiles (incluidas las variables largas y dobles).

¡Aclamaciones!


La clave volátil cuando se usa con una variable, se asegurará de que los hilos que leen esta variable vean el mismo valor. Ahora, si tiene varios subprocesos que leen y escriben en una variable, hacer que la variable sea volátil no será suficiente y los datos se corromperán. Las secuencias de imágenes han leído el mismo valor, pero cada una ha hecho algunos cambios (por ejemplo, un contador incrementado), al escribir en la memoria, se viola la integridad de los datos. Es por eso que es necesario hacer que la variedad sea sincronizada (diferentes formas son posibles)

Si los cambios se realizan mediante 1 subproceso y los demás solo necesitan leer este valor, la volatilidad será adecuada.


Las variables volátiles son la sincronización ligera. Cuando la visibilidad de los últimos datos entre todos los subprocesos es un requisito y la atomicidad puede verse comprometida, en tales situaciones deben preferirse las variables volátiles. Leer sobre variables volátiles siempre devuelve la escritura más reciente realizada por cualquier hilo, ya que no se almacenan en caché en registros ni en cachés donde otros procesadores no pueden ver. Volatile is Lock-Free. Yo uso volátil, cuando el escenario cumple con los criterios mencionados anteriormente.


Lo volátil lo sigue.

1> La lectura y escritura de variables volátiles por diferentes subprocesos provienen siempre de la memoria, no de la caché del propio subproceso o del registro de la CPU. Así que cada hilo siempre trata con el último valor. 2> Cuando 2 subprocesos diferentes funcionan con la misma instancia o variables estáticas en el montón, uno puede ver las acciones de otros como fuera de orden. Ver el blog de jeremy manson sobre esto. Pero las ayudas volátiles aquí.

El siguiente código en ejecución muestra cómo una serie de subprocesos pueden ejecutarse en un orden predefinido e imprimir salidas sin usar palabras clave sincronizadas.

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 utilizar el siguiente código de ejecución completo.

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 archivo Léame, que proporciona una explicación adecuada. https://github.com/sankar4git/volatile_thread_ordering


Me gusta la explicacion jenkov

La palabra clave volátil de Java se utiliza para marcar una variable de Java como "almacenada en la memoria principal". Más precisamente, eso significa que cada lectura de una variable volátil se leerá desde la memoria principal de la computadora y no desde la memoria caché de la CPU, y que cada escritura en una variable volátil se escribirá en la memoria principal, y no solo en la memoria caché de la CPU .

En realidad, como Java 5, la palabra clave volátil garantiza algo más que las variables volátiles que se escriben y leen desde la memoria principal. Se trata de una garantía de visibilidad extendida llamada garantía de suceso antes.

Consideraciones de rendimiento de volátiles

La lectura y escritura de variables volátiles hace que la variable se lea o escriba en la memoria principal. Leer y escribir en la memoria principal es más costoso que acceder a la memoria caché de la CPU. El acceso a las variables volátiles también evita que se reordene la instrucción, que es una técnica normal de mejora del rendimiento. Por lo tanto, solo debe usar variables volátiles cuando realmente necesite hacer cumplir la visibilidad de las variables.


Nadie ha mencionado el tratamiento de lectura y escritura para el tipo de variable larga y doble. Las lecturas y escrituras son operaciones atómicas para variables de referencia y para la mayoría de las variables primitivas, excepto para los tipos de variables largas y dobles, que deben usar la palabra clave volátil para ser operaciones atómicas. @link


Sí, lo uso bastante; puede ser muy útil para el código de subprocesos múltiples. El artículo que mencionaste es bueno. Aunque hay dos cosas importantes a tener en cuenta:

  1. Solo debe usar volatile si entiende completamente lo que hace y cómo difiere en la sincronización. En muchas situaciones, volátil aparece, en la superficie, como una alternativa más simple y más eficiente a la sincronización, cuando a menudo una mejor comprensión de la volatilidad dejaría en claro que la única opción que funcionaría sería la sincronización.
  2. volatile en realidad no funciona en muchas JVM antiguas, aunque sí lo hace la sincronización. Recuerdo haber visto un documento que hacía referencia a los diversos niveles de soporte en diferentes JVM, pero desafortunadamente no lo puedo encontrar ahora. Definitivamente, investigue si está utilizando Java pre 1.5 o si no tiene control sobre las JVM en las que se ejecutará su programa.

Sí, volatile se debe usar siempre que desee que varias subprocesos accedan a una variable mutable. No es un caso de uso muy común porque normalmente necesita realizar más de una sola operación atómica (p. Ej., Verificar el estado de la variable antes de modificarla), en cuyo caso usaría un bloque sincronizado.


Tendrá que usar palabras clave ''volátiles'' o ''sincronizadas'' y cualquier otra herramienta y técnica de control de concurrencia que pueda tener a su disposición si está desarrollando una aplicación de multiproceso. Ejemplo de tal aplicación es aplicaciones de escritorio.

Si está desarrollando una aplicación que se implementaría en el servidor de aplicaciones (Tomcat, JBoss AS, Glassfish, etc.), no tiene que manejar el control de concurrencia como ya lo abordó el servidor de aplicaciones. De hecho, si recordaba correctamente, el estándar Java EE prohíbe cualquier control de concurrencia en servlets y EJBs, ya que es parte de la capa de ''infraestructura'' que se supone que debe liberarse de su manejo. Solo hace el control de concurrencia en dicha aplicación si está implementando objetos singleton. Esto incluso se aborda si teje tus componentes utilizando frameworkd como Spring.

Por lo tanto, en la mayoría de los casos de desarrollo de Java donde la aplicación es una aplicación web y utiliza un marco de IoC como Spring o EJB, no tendría que usar "volátil".


Un ejemplo común para usar volatile es usar una variable volatile boolean como una bandera para terminar un hilo. Si ha iniciado un hilo y desea poder interrumpirlo con seguridad desde un hilo diferente, puede hacer que el hilo verifique periódicamente una bandera. Para detenerlo, establece la bandera en verdadero. Al hacer que el indicador sea volatile , puede asegurarse de que el hilo que está verificando verá que se configuró la próxima vez que lo verifique sin tener que usar un bloque synchronized .


Una variable volátil se modifica de forma asíncrona mediante la ejecución simultánea de subprocesos en una aplicación Java. No está permitido tener una copia local de una variable que sea diferente del valor que se tiene actualmente en la memoria "principal". Efectivamente, una variable declarada volátil debe tener sus datos sincronizados en todos los subprocesos, de modo que cada vez que acceda o actualice la variable en cualquier subproceso, todos los demás subprocesos verán inmediatamente el mismo valor. Por supuesto, es probable que las variables volátiles tengan un mayor costo de acceso y actualización que las variables "simples", ya que la razón por la cual los hilos pueden tener su propia copia de datos es para una mejor eficiencia.

Cuando un campo se declara volátil, el compilador y el tiempo de ejecución se comunican que esta variable se comparte y que las operaciones en él no se deben reordenar con otras operaciones de memoria. Las variables volátiles no se almacenan en caché en registros ni en cachés donde están ocultos de otros. procesadores, por lo que una lectura de una variable volátil siempre devuelve la escritura más reciente por cualquier hilo.

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


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

  1. Si tenemos una variable volátil, no se puede almacenar en la memoria caché de la computadora (microprocesador) por ningún hilo. El acceso siempre sucedió desde la memoria principal.

  2. Si hay una operación de escritura en una variable volátil y de repente se solicita una operación de lectura , se garantiza que la operación de escritura finalizará antes de la operación de lectura .

Dos cualidades anteriores deducen que

  • Todos los hilos que leen una variable volátil definitivamente leerán el último valor. Porque ningún valor almacenado en caché puede contaminarlo. Y también la solicitud de lectura se otorgará solo después de la finalización de la operación de escritura actual.

Y por otro lado,

  • Si investigamos más a fondo el # 2 que he mencionado, podemos ver que la palabra clave volatile es una forma ideal de mantener una variable compartida que tiene ''n'' número de subprocesos de lectura y solo un subproceso de escritura para acceder a ella. Una vez que agregamos la palabra clave volatile , se hace. No hay ninguna otra sobrecarga sobre la seguridad del hilo.

A la inversa

No podemos hacer uso exclusivo de palabras clave volatile , para satisfacer una variable compartida que tiene más de un hilo de escritura accediendo a ella .


volátil es muy útil para detener hilos.

No es que debas escribir tus propios subprocesos, Java 1.6 tiene muchos conjuntos de subprocesos agradables. Pero si está seguro de que necesita un hilo, deberá saber cómo detenerlo.

El patrón que uso para los 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 que no hay necesidad de sincronización


volatile solo garantiza que todos los hilos, incluso ellos mismos, se están incrementando. Por ejemplo: un contador ve la misma cara de la variable al mismo tiempo. No se utiliza en lugar de sincronizado o atómico u otras cosas, hace que las lecturas estén completamente sincronizadas. Por favor, no lo compare con otras palabras clave de Java. Como el ejemplo que se muestra a continuación, las operaciones de variables volátiles también son atómicas, fallan o tienen é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 pones resultados volátiles o no siempre serán diferentes. Pero si usa AtomicInteger como se muestra a continuación, los resultados serán siempre los mismos. Esto es igual con sincronizado 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); } } }


volatile tiene semántica para la visibilidad de la memoria. Básicamente, el valor de un campo volatile vuelve visible para todos los lectores (en particular, otros hilos) después de que se complete una operación de escritura en él. Sin volatile , los lectores podrían ver algún valor no actualizado.

Para responder a su pregunta: Sí, uso una variable volatile para controlar si un código continúa un ciclo. El bucle prueba el valor volatile y continúa si es true . La condición se puede establecer en false llamando a un método de "parada". El bucle ve false y termina cuando prueba el valor después de que el método de detención completa la ejecución.

El libro " Java Concurrency in Practice ", que recomiendo ampliamente, brinda una buena explicación de la volatile . Este libro está escrito por la misma persona que escribió el artículo de IBM al que se hace referencia en la pregunta (de hecho, cita su libro al final de ese artículo). Mi uso de volatile es lo que su artículo llama "indicador de estado del patrón 1".

Si desea obtener más información sobre cómo funciona la volatile bajo el capó, lea el modelo de memoria de Java . Si desea ir más allá de ese nivel, consulte un buen libro de arquitectura de computadoras como Hennessy & Patterson y lea sobre la coherencia de la memoria caché y la consistencia de la memoria caché.


"... el modificador volátil garantiza que cualquier hilo que lea un campo verá el último valor escrito". - Josh Bloch

Si está pensando en usar volatile , lea el paquete java.util.concurrent que trata sobre el comportamiento atómico.

La publicación de Wikipedia en un patrón Singleton muestra volátil en uso.


Punto importante sobre la volatile :

  1. La sincronización en Java es posible usando palabras clave de Java synchronized y volatile y bloqueos.
  2. En Java, no podemos tener synchronized variable synchronized . El uso de palabras clave synchronized con una variable es ilegal y dará lugar a un error de compilación. En lugar de usar la variable synchronized en Java, puede usar la variable volatile Java, que le indicará a los subprocesos de la JVM que lean el valor de la variable volatile de la memoria principal y no la almacenen en la caché localmente.
  3. Si una variable no se comparte entre varios subprocesos, no es necesario utilizar la palabra clave volatile .

source

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 la instancia perezosamente en el momento en que llega la primera solicitud.

Si no hacemos volatile variable _instance , entonces el subproceso que crea la instancia de Singleton no puede comunicarse con el otro subproceso. Por lo tanto, si el subproceso A está creando una instancia de Singleton y justo después de la creación, la CPU se corrompe, etc., todos los demás subprocesos no podrán ver el valor de _instance como no nulo y creerán que aún se asigna como nulo.

¿Por qué pasó esto? Debido a que los hilos del lector no están bloqueando y hasta que el hilo del escritor sale de un bloque sincronizado, la memoria no se sincronizará y el valor de _instance no se actualizará en la memoria principal. Con la palabra clave Volatile en Java, esto es manejado por el mismo Java y dichas actualizaciones serán visibles por todos los hilos del lector.

Conclusión : la palabra clave volatile también se utiliza para comunicar el contenido de la memoria entre subprocesos.

Ejemplo de uso de sin volatile:

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 seguro para subprocesos. Aunque comprueba el valor de la instancia una vez más dentro del bloque sincronizado (por razones de rendimiento), el compilador JIT puede reorganizar el bytecode de manera que la referencia a la instancia se establezca antes de que el constructor finalice su ejecución. Esto significa que el método getInstance () devuelve un objeto que puede no haberse inicializado completamente. Para hacer que el código sea seguro para el subproceso, la palabra clave volátil se puede usar desde Java 5 para la variable de instancia. Las variables que están marcadas como volátiles solo son visibles para otros subprocesos una vez que el constructor del objeto ha finalizado completamente su ejecución.
Source

Uso volatile en Java :

Los iteradores a prueba de fallas generalmente se implementan usando un contador volatile en el objeto de lista.

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

La implementación de iteradores a prueba de fallas es típicamente liviana. Por lo general, dependen de las propiedades de las estructuras de datos de la implementación de la lista específica. No hay un patrón general.