Volatile vs statique en Java


265

Est-il correct de dire que cela staticsignifie une copie de la valeur pour tous les objets et volatilesignifie une copie de la valeur pour tous les threads?

Quoi qu'il en soit, une staticvaleur variable va également être une valeur pour tous les threads, alors pourquoi devrions-nous y aller volatile?


Réponses:


365

La déclaration d'une variable statique en Java signifie qu'il n'y aura qu'une seule copie, quel que soit le nombre d'objets de la classe créés. La variable sera accessible même sans aucune Objectscréation. Cependant, les threads peuvent en avoir des valeurs mises en cache localement.

Lorsqu'une variable est volatile et non statique , il y aura une variable pour chacune Object. Donc, en surface, il ne semble pas y avoir de différence par rapport à une variable normale mais totalement différente de statique . Cependant, même avec des Objectchamps, un thread peut mettre en cache une valeur variable localement.

Cela signifie que si deux threads mettent à jour une variable du même objet simultanément et que la variable n'est pas déclarée volatile, il peut y avoir un cas dans lequel l'un des threads a en cache une ancienne valeur.

Même si vous accédez à une valeur statique via plusieurs threads, chaque thread peut avoir sa copie en cache locale! Pour éviter cela, vous pouvez déclarer la variable comme volatile statique et cela forcera le thread à lire chaque fois la valeur globale.

Cependant, volatile ne remplace pas une bonne synchronisation!
Par exemple:

private static volatile int counter = 0;

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

L'exécution concurrentMethodWrongsimultanée de plusieurs fois peut conduire à une valeur finale de compteur différente de zéro!
Pour résoudre le problème, vous devez implémenter un verrou:

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;
  }
}

Ou utilisez la AtomicIntegerclasse.


7
Le modificateur volatile garantit que tout thread qui lit un champ verra la dernière valeur écrite, il est donc nécessaire si la variable est partagée entre plusieurs threads et que vous avez besoin de cette fonctionnalité, cela dépend de votre cas d'utilisation.
stivlo

5
Qu'est-ce que le cache lorsque vous dites "mis en cache localement"? Cache CPU, une sorte de cache JVM?
mert inan

6
@mertinan oui, la variable peut se trouver dans un cache plus proche du processeur ou du coeur. Voir cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html pour plus de détails.
stivlo

15
«volatile» n'implique pas «une variable par objet». L'absence de «statique» fait cela. -1 pour ne pas avoir clarifié cette idée fausse élémentaire de la part du PO.
Marquis de Lorne

27
@EJP Je pensais que la phrase "Déclarer une variable comme volatile, il y aura une variable pour chaque objet. Donc en surface, il semble qu'il n'y ait pas de différence avec une variable normale" expliquait que, j'ai ajouté et non statique , n'hésitez pas à modifier l'article et à améliorer la formulation pour le rendre plus clair.
stivlo

288

Différence entre statique et volatile:

Variable statique : si deux threads (supposons t1et t2) accèdent au même objet et mettent à jour une variable qui est déclarée comme statique, cela signifie t1et t2peuvent créer leur propre copie locale du même objet (y compris les variables statiques) dans leur cache respectif, alors mettez à jour faite par t1la variable statique dans son cache local ne se reflétera pas dans la variable statique du t2cache.

Les variables statiques sont utilisées dans le contexte d'Object où la mise à jour effectuée par un objet se refléterait dans tous les autres objets de la même classe mais pas dans le contexte de Thread où la mise à jour d'un thread vers la variable statique reflètera les changements immédiatement à tous les threads (dans leur cache local).

Variable volatile : si deux threads (supposons t1et t2) accèdent au même objet et mettent à jour une variable qui est déclarée volatile, cela signifie t1et t2peuvent créer leur propre cache local de l'objet, sauf la variable qui est déclarée volatile . Ainsi, la variable volatile n'aura qu'une seule copie principale qui sera mise à jour par différents threads et la mise à jour effectuée par un thread sur la variable volatile se reflétera immédiatement sur l'autre thread.


6
Bonjour @Som, veuillez me corriger si je me trompe. Mais ne pensez-vous pas que la déclaration « mais pas dans le contexte de Thread où la mise à jour d'un thread à la variable statique reflétera immédiatement les modifications apportées à tous les threads (dans leur cache local). » Devrait être «mais pas dans le contexte de Thread où la mise à jour d'un thread à la variable statique reflétera <<NOT>> immédiatement les modifications apportées à tous les threads (dans leur cache local). "
Jaikrat

@Jaikrat Oui, c'était très déroutant pour moi. Je crois comprendre que vous avez raison et que cette réponse est fausse, comme écrit. Je voudrais également être corrigé si je me trompe.
stuart

@Jaikrat Threads ne met pas en cache les variables statiques, mais référez-vous aux variables statiques mises à jour.
Som

@Som Alors voudriez-vous corriger le para et le supprimer mais pas dans le contexte de Thread . C'est très déroutant. Merci
Jaikrat

Malheureusement, cette réponse est incorrecte. Sur les processeurs modernes, même une volatilevariable peut être partagée entre des caches de processeur distincts. Cela ne pose aucun problème car le cache négocie la propriété exclusive de la ligne de cache avant de la modifier.
David Schwartz

32

En plus d'autres réponses, je voudrais ajouter une image pour elle (la photo est facile à comprendre)

entrez la description de l'image ici

staticles variables peuvent être mises en cache pour des threads individuels. Dans un environnement multithread si un thread modifie ses données en cache, cela peut ne pas refléter pour les autres threads car ils en ont une copie .

volatilegarantit que les threads ne mettront pas en cache les données et utilise uniquement la copie partagée .

source d'image


1
les variables statiques sont partagées entre les objets sous un thread? Cela devrait lire les variables statiques sont partagées entre les objets tous les objets indépendamment des threads.
cquezel

1
"les variables volatiles sont partagées entre plusieurs threads (donc les objets aussi)." Volatile ne change pas la façon dont les variables sont partagées entre plusieurs threads ou objets. Il modifie la façon dont le runtime est autorisé à mettre en cache la valeur.
cquezel

1
Votre commentaire sur les variables statiques s'applique également aux variables non statiques et les mots "seront mis en cache" et "ne refléteront pas" devraient probablement être reformulés "peuvent être mis en cache" et "peuvent ne pas refléter".
cquezel

4
J'étais très confus. cette photo a effacé toutes mes questions!
vins

5

Je pense staticet volatilen'ai aucune relation du tout. Je vous suggère de lire le tutoriel java pour comprendre l'accès atomique , et pourquoi utiliser l'accès atomique, comprendre ce qui est entrelacé , vous trouverez la réponse.


4

En termes simples,

  1. statique : les staticvariables sont associées à la classe , plutôt qu'à n'importe quel objet . Chaque instance de la classe partage une variable de classe, qui se trouve dans un emplacement fixe en mémoire

  2. volatile : ce mot-clé s'applique aux variables de classe et d' instance .

L'utilisation de variables volatiles réduit le risque d'erreurs de cohérence de la mémoire, car toute écriture dans une variable volatile établit une relation passe-avant avec les lectures suivantes de cette même variable. Cela signifie que les modifications apportées à une variable volatile sont toujours visibles pour les autres threads

Jetez un oeil à cet article par Javin Paul comprendre les variables volatiles d'une manière mieux.

entrez la description de l'image ici

En l'absence de volatilemot-clé, la valeur de la variable dans la pile de chaque thread peut être différente. En créant la variable as volatile, tous les threads obtiendront la même valeur dans leur mémoire de travail et les erreurs de cohérence de la mémoire ont été évitées.

Ici, le terme variablepeut être une staticvariable (classe) ou une variable instance(objet).

Concernant votre requête:

Quoi qu'il en soit, une valeur de variable statique va également être une valeur pour tous les threads, alors pourquoi devrions-nous opter pour volatile?

Si j'ai besoin de instancevariable dans mon application, je ne peux pas utiliser de staticvariable. Même en cas de staticvariable, la cohérence n'est pas garantie en raison du cache de thread comme indiqué dans le diagramme.

L'utilisation de volatilevariables réduit le risque d'erreurs de cohérence de la mémoire, car toute écriture dans une variable volatile établit une relation passe-avant avec les lectures suivantes de cette même variable. Cela signifie que les modifications apportées à une variable volatile sont toujours visibles pour les autres threads.

De plus, cela signifie également que lorsqu'un thread lit une variable volatile, il voit non seulement la dernière modification apportée à la volatile, mais également les effets secondaires du code qui a provoqué la modification => des erreurs de cohérence de la mémoire sont toujours possibles avec des variables volatiles . Pour éviter les effets secondaires, vous devez utiliser des variables synchronisées. Mais il existe une meilleure solution en java.

L'utilisation d'un accès aux variables atomiques simple est plus efficace que l'accès à ces variables via un code synchronisé

Certaines classes du java.util.concurrentpackage fournissent des méthodes atomiques qui ne dépendent pas de la synchronisation.

Reportez-vous à cet article de contrôle de concurrence de haut niveau pour plus de détails.

Jetez un œil aux variables atomiques .

Questions SE connexes:

Volatile contre atomique

Volatile booléen vs AtomicBoolean

Différence entre volatile et synchronisé en Java


J'apprécie vraiment cette réponse. Je savais ce qui est le volatileplus tôt, mais cette réponse clarifie beaucoup pour moi pourquoi dois-je encore utiliser volatileavec la staticvariable.
Chaklader Asfak Arefe

volatile: ce mot-clé s'applique aux variables de classe et d'instance. La déclaration que vous avez dit ci-dessus est incorrecte concernant applicable à la classe. seuls deux mots clés applicables à la variable sont volatils et transitoires. si volatile ne s'applique pas pour la classe.
ASR

volatile est applicable aux variables de classe (statiques). Vérifiez les liens singleton verrouillés double dans Google et vous pouvez constater que votre compréhension est fausse. stackoverflow.com/questions/18093735/…
Ravindra babu

volatile statique privé est une déclaration valide.
Ravindra babu

0

l'accès aux valeurs variables volatiles se fera directement depuis la mémoire principale. Il ne doit être utilisé que dans un environnement multithread. la variable statique sera chargée une fois. Si elle est utilisée dans un environnement à thread unique, même si la copie de la variable sera mise à jour et qu'il n'y aura aucun mal à y accéder car il n'y a qu'un seul thread.

Maintenant, si une variable statique est utilisée dans un environnement multi-threading, il y aura des problèmes si l'on attend le résultat souhaité de celle-ci. Comme chaque thread a sa propre copie, tout incrément ou décrément sur la variable statique d'un thread peut ne pas se refléter dans un autre thread.

si l'on attend les résultats souhaités de la variable statique, puis utilisez volatile avec statique dans le multi-threading, tout sera résolu.


0

Pas sûr que les variables statiques soient mises en cache dans la mémoire locale du thread ou NON. Mais lorsque j'ai exécuté deux threads (T1, T2) accédant au même objet (obj) et lors de la mise à jour effectuée par le thread T1 en variable statique, cela s'est reflété dans T2.


-2

Si nous déclarons une variable statique, il n'y aura qu'une seule copie de la variable. Ainsi, chaque fois que différents threads accèdent à cette variable, il n'y aura qu'une seule valeur finale pour la variable (car il n'y a qu'un seul emplacement mémoire alloué pour la variable).

Si une variable est déclarée volatile, tous les threads auront leur propre copie de la variable mais la valeur est extraite de la mémoire principale. Ainsi, la valeur de la variable dans tous les threads sera la même.

Donc, dans les deux cas, le point principal est que la valeur de la variable est la même sur tous les threads.


15
Si une variable est déclarée volatile, tous les threads auront leur propre copie de la variable mais la valeur est prise dans la mémoire principale. => à droite. Ainsi, la valeur de la variable dans tous les threads sera la même. => faux, chaque thread utilisera la même valeur pour le même objet, mais chaque objet aura sa propre copie.
Stivlo
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.