Volátil vs Estático en Java


265

¿Es correcto decir que staticsignifica una copia del valor para todos los objetos y volatileuna copia del valor para todos los hilos?

De todos modos, un staticvalor variable también será un valor para todos los hilos, entonces, ¿por qué deberíamos elegir volatile?


Respuestas:


365

Declarar una variable estática en Java significa que solo habrá una copia, sin importar cuántos objetos de la clase se creen. La variable será accesible incluso sin ninguna Objectscreación. Sin embargo, los subprocesos pueden tener valores almacenados en caché localmente.

Cuando una variable es volátil y no estática , habrá una variable para cada una Object. Entonces, en la superficie parece que no hay diferencia con respecto a una variable normal, pero es totalmente diferente de la estática . Sin embargo, incluso con Objectcampos, un subproceso puede almacenar en caché un valor variable localmente.

Esto significa que si dos subprocesos actualizan una variable del mismo Objeto al mismo tiempo, y la variable no se declara volátil, podría haber un caso en el que uno de los subprocesos tenga en la memoria caché un valor antiguo.

Incluso si accede a un valor estático a través de múltiples hilos, ¡cada hilo puede tener su copia local en caché! Para evitar esto, puede declarar la variable como estática volátil y esto obligará al hilo a leer cada vez que el valor global.

Sin embargo, ¡ volátil no es un sustituto de la sincronización adecuada!
Por ejemplo:

private static volatile int counter = 0;

private void concurrentMethodWrong() {
  counter = counter + 5;
  //do something
  counter = counter - 5;
}

¡Ejecutar concurrentMethodWrongsimultáneamente muchas veces puede conducir a un valor final de contador diferente de cero!
Para resolver el problema, debe implementar un bloqueo:

private static final Object counterLock = new Object();

private static volatile int counter = 0;

private void concurrentMethodRight() {
  synchronized (counterLock) {
    counter = counter + 5;
  }
  //do something
  synchronized (counterLock) {
    counter = counter - 5;
  }
}

O usa la AtomicIntegerclase.


77
El modificador volátil garantiza que cualquier subproceso que lea un campo verá el valor escrito más recientemente, por lo que es necesario si la variable se comparte entre varios subprocesos y necesita esta función, depende de su caso de uso.
stivlo

55
¿Qué es el caché cuando dices "en caché local"? ¿Caché de CPU, algún tipo de caché JVM?
Mert inan

66
@mertinan sí, la variable puede estar en una caché más cercana al procesador o núcleo. Consulte cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html para obtener más detalles.
stivlo

15
'volátil' no implica 'una variable por objeto'. La ausencia de "estática" hace eso. -1 por no aclarar esta idea errónea elemental por parte del OP.
Marqués de Lorne

27
@EJP Pensé que la oración "Declarando una variable como volátil, habrá una variable para cada Objeto. Entonces, en la superficie parece que no hay diferencia con respecto a una variable normal", explicaba que, he agregado y no estático , siéntase libre de editar el artículo y mejorar la redacción para hacerlo más claro.
stivlo

288

Diferencia entre estática y volátil:

Variable estática : Si dos hilos (supongamos t1e t2) acceden al mismo objeto y la actualización de una variable que se declara como estática y entonces significa t1y t2puede hacer su propia copia local del mismo objeto (incluyendo las variables estáticas) en sus respectivos caché, por lo que la actualización hecho por t1la variable estática en su caché local no se reflejará en la variable estática para t2caché.

Las variables estáticas se usan en el contexto de Object donde la actualización realizada por un objeto se reflejaría en todos los demás objetos de la misma clase pero no en el contexto de Thread donde la actualización de un thread a la variable estática reflejará los cambios inmediatamente a todos los subprocesos (en su caché local).

Variables volátiles : Si dos hilos (supongamos t1e t2) acceden al mismo objeto y la actualización de una variable que se declara tan volátil, entonces significa t1y t2puede hacer su propia caché local del objeto , excepto la variable que se declara como una volátil . Por lo tanto, la variable volátil tendrá solo una copia principal que será actualizada por diferentes hilos y la actualización realizada por un hilo a la variable volátil se reflejará inmediatamente en el otro hilo.


66
Hola @Som, corrígeme si me equivoco. Pero no cree que la declaración " pero no en el contexto de Thread donde la actualización de un hilo a la variable estática reflejará los cambios inmediatamente a todos los hilos (en su caché local) " debería ser "pero no en el contexto de subproceso donde la actualización de un subproceso a la variable estática <<NOT>> reflejará los cambios inmediatamente a todos los subprocesos (en su caché local) ".
Jaikrat

@Jaikrat Sí, eso fue muy confuso para mí. Entiendo que tienes razón y que esta respuesta es incorrecta, tal como está escrita. También me gustaría que me corrijan si me equivoco.
stuart

Los hilos de @Jaikrat no almacenan en caché las variables estáticas, pero sí se refieren a las variables estáticas actualizadas.
Som

@Som Entonces, ¿le gustaría corregir el para y eliminar, pero no en el contexto de Thread . Eso es muy confuso. Gracias
Jaikrat

Lamentablemente, esta respuesta es incorrecta. En las CPU modernas, incluso una volatilevariable se puede compartir entre distintos cachés de CPU. Esto no presenta ningún problema porque la caché negocia la propiedad exclusiva de la línea de caché antes de modificarla.
David Schwartz

32

Además de otras respuestas, me gustaría agregarle una imagen (la foto hace que sea fácil de entender)

ingrese la descripción de la imagen aquí

staticLas variables pueden almacenarse en caché para subprocesos individuales. En un entorno de subprocesos múltiples, si un subproceso modifica sus datos en caché, es posible que no se reflejen para otros subprocesos, ya que tienen una copia de él.

volatileLa declaración garantiza que los subprocesos no almacenarán en caché los datos y utiliza solo la copia compartida .

fuente de imagen


1
Las variables estáticas se comparten entre los objetos debajo de un hilo? Esto debería leer las variables estáticas se comparten entre los objetos, todos los objetos, independientemente de los hilos.
cquezel

1
"las variables volátiles se comparten entre múltiples subprocesos (también los objetos)". Volátil no cambia la forma en que las variables se comparten entre múltiples hilos u objetos. Cambia cómo se permite que el tiempo de ejecución almacene en caché el valor.
cquezel

1
Su comentario sobre las variables estáticas también se aplica a las no estáticas y el "será almacenado en caché" y "no se reflejará" probablemente debería reformularse "puede almacenarse en caché" y "puede no reflejarse".
cquezel

44
Estaba muy confundido ¡Esta foto borró todas mis preguntas!
vins

5

Pienso staticy volatileno tengo ninguna relación en absoluto. Le sugiero que lea el tutorial de Java para comprender el acceso atómico , y por qué usar el acceso atómico, comprender lo que está entrelazado , encontrará la respuesta.


4

En lenguaje sencillo,

  1. estática : las staticvariables están asociadas con la clase , en lugar de con cualquier objeto . Cada instancia de la clase comparte una variable de clase, que está en una ubicación fija en la memoria

  2. volátil : esta palabra clave es aplicable tanto a las variables de clase como de instancia .

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 anterior con lecturas posteriores de esa misma variable. Esto significa que los cambios en una variable volátil siempre son visibles para otros hilos

Echar un vistazo a este artículo por Javin Paul entender las variables volátiles de una mejor manera.

ingrese la descripción de la imagen aquí

En ausencia de volatilepalabra clave, el valor de la variable en la pila de cada subproceso puede ser diferente. Al hacer la variable como volatile, todos los hilos obtendrán el mismo valor en su memoria de trabajo y se evitarán los errores de consistencia de la memoria.

Aquí el término variablepuede ser staticvariable (clase) o variable instance(objeto).

Con respecto a su consulta:

De todos modos, un valor de variable estática también será un valor para todos los hilos, entonces ¿por qué deberíamos elegir volátil?

Si necesito instancevariable en mi aplicación, no puedo usar staticvariable. Incluso en caso de staticvariable, no se garantiza la coherencia debido a la memoria caché de subprocesos como se muestra en el diagrama.

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

Además, también significa que cuando un hilo lee una variable volátil, ve no solo el último cambio en el volátil, sino también los efectos secundarios del código que provocó el cambio => los errores de consistencia de memoria aún son posibles con variables volátiles . Para evitar los efectos secundarios, debe usar variables sincronizadas. Pero hay una mejor solución en Java.

El uso del acceso simple a la variable atómica es más eficiente que acceder a estas variables a través del código sincronizado

Algunas de las clases en el java.util.concurrentpaquete proporcionan métodos atómicos que no dependen de la sincronización.

Consulte este artículo de control de concurrencia de alto nivel para obtener más detalles.

Especialmente eche un vistazo a las variables atómicas .

Preguntas SE relacionadas:

Volátil Vs Atómico

Boolean volátil vs AtomicBoolean

Diferencia entre volátil y sincronizado en Java


Realmente aprecio esta respuesta. Sabía lo que era volatileantes, pero esta respuesta me aclara mucho por qué todavía necesito usar volatilela staticvariable.
Chaklader Asfak Arefe

volátil: esta palabra clave es aplicable tanto a las variables de clase como de instancia. La declaración que dijo anteriormente es incorrecta con respecto a aplicable a la clase. solo dos palabras clave que se aplican a variable son volátiles y transitorias. tan volátil no aplicable para la clase.
ASR

volátil es aplicable a las variables de clase (estáticas). Echa un vistazo a los enlaces singleton de doble bloqueo en google y puedes encontrar que tu comprensión es incorrecta. stackoverflow.com/questions/18093735/…
Ravindra babu

La volatilidad estática privada es una declaración válida.
Ravindra babu

0

El acceso a valores variables volátiles será directo desde la memoria principal. Debe usarse solo en entornos de subprocesos múltiples. La variable estática se cargará una vez. Si se usa en un entorno de subproceso único, incluso si la copia de la variable se actualizará y no habrá ningún daño al acceder, ya que solo hay un subproceso.

Ahora, si se usa una variable estática en un entorno de subprocesos múltiples, habrá problemas si se espera el resultado deseado. Como cada subproceso tiene su propia copia, cualquier incremento o disminución en la variable estática de un subproceso puede no reflejarse en otro subproceso.

Si uno espera los resultados deseados de la variable estática, use volátil con estática en subprocesos múltiples y todo se resolverá.


0

No estoy seguro de que las variables estáticas se almacenen en caché en la memoria local de subprocesos o NO. Pero cuando ejecuté dos subprocesos (T1, T2) accediendo al mismo objeto (obj) y cuando la actualización realizada por el subproceso T1 a la variable estática se reflejó en T2.


-2

Si declaramos una variable como estática, solo habrá una copia de la variable. Entonces, cada vez que diferentes hilos accedan a esa variable, solo habrá un valor final para la variable (ya que solo hay una ubicación de memoria asignada para la variable).

Si una variable se declara como volátil, todos los subprocesos tendrán su propia copia de la variable, pero el valor se tomará de la memoria principal, por lo que el valor de la variable en todos los subprocesos será el mismo.

Entonces, en ambos casos, el punto principal es que el valor de la variable es el mismo en todos los hilos.


15
Si una variable se declara como volátil, todos los subprocesos tendrán su propia copia de la variable, pero el valor se tomará de la memoria principal. => derecha. Entonces, el valor de la variable en todos los hilos será el mismo. => incorrecto, cada subproceso utilizará el mismo valor para el mismo objeto, pero cada objeto tendrá su propia copia.
stivlo
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.