web-dev-qa-db-fra.com

Volatile vs Static dans Java

Est-il correct de dire que static signifie une copie de la valeur pour tous les objets et volatile une copie de la valeur pour tous les threads?

Quoi qu'il en soit, une valeur de variable static sera également une valeur pour tous les threads, alors pourquoi devrions-nous choisir volatile?

255
Jothi

Déclarer une variable statique 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 si aucun Objects n'a été créé. Cependant, les threads peuvent en avoir des valeurs mises en cache localement.

Quand une variable est volatile et non statique , il y aura une variable pour chaque Object. Donc, à première vue, il semble qu'il n'y ait pas de différence par rapport à une variable normale mais totalement différent de statique . Cependant, même avec les champs Object, un thread peut mettre en cache une valeur de 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 arriver que l'un des threads ait dans le 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 statique volatile , ce qui obligera le thread à lire chaque fois la valeur globale.

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

private static volatile int counter = 0;

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

L'exécution simultanée de concurrentMethodWrong peut conduire à une valeur de compteur finale 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 classe AtomicInteger .

351
stivlo

Différence entre statique et volatil:

Variable statique: Si deux threads (supposons t1 et t2) accèdent au même objet et mettent à jour une variable déclarée statique, cela signifie t1 et t2 peut créer sa propre copie locale du même objet (y compris les variables statiques) dans son cache respectif. La mise à jour effectuée par t1 vers la variable statique de son cache local ne sera donc pas reflétée dans la variable statique de t2 cache.

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

Variable volatile: Si deux threads (supposons t1 et t2) accèdent au même objet et mettent à jour une variable déclarée volatile, cela signifie t1 et t2 peut créer son propre cache local de Object à l'exception de la variable déclarée volatile. Ainsi, la variable volatile aura 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 sera immédiatement répercutée sur l'autre thread.

283
Som

En plus d’autres réponses, je voudrais ajouter une image à cet effet (la photo est facile à comprendre)

enter image description here

static les variables peuvent être mises en cache pour des threads individuels. Dans un environnement multi-thread , si un thread modifie ses données mises en cache, il est possible que cela ne soit pas le cas pour les autres threads car ils en ont une copie .

La déclaration volatile s'assure que les threads ne mettent pas les données en cache et utilise uniquement la copie partagée .

source de l'image

26
mrsrinivas

Je pense que static et volatile n'ont aucun rapport. Je vous suggère de lire Java tutoriel pour comprendre Accès atomique , et pourquoi utiliser l'accès atomique, comprendre ce qui est entrelacé , vous trouverez la réponse.

5
Amitābha

En termes simples,

  1. statique : static les variables sont associées à la classe , plutôt qu'avec 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é est applicable à la fois à la classe et à instance variables.

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 par les autres threads.

Jetez un oeil à ceci article de Javin Paul pour mieux comprendre les variables volatiles.

enter image description here

En l'absence du mot clé volatile, la valeur de la variable dans la pile de chaque thread peut être différente. En faisant de la variable volatile, tous les threads auront 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 variable peut être soit static variable (classe), soit instance variable (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 la variable instance dans mon application, je ne peux pas utiliser la variable static. Même dans le cas de la variable static, la cohérence n'est pas garantie en raison du cache de thread, comme indiqué dans le diagramme.

L'utilisation de variables volatile 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 par les autres threads.

De plus, cela signifie également que lorsqu'un thread lit une variable volatile, il ne voit pas seulement la dernière modification de la variable 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 simple accès à une variable atomique est plus efficace qu'un accès à ces variables via un code synchronisé

Certaines des classes du package Java.util.concurrent fournissent des méthodes atomiques qui ne reposent pas sur la synchronisation.

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

Surtout jetez un oeil à variables atomiques .

Questions SE connexes:

Volatile Vs Atomic

booléen volatil vs AtomicBoolean

Différence entre volatile et synchronisé en Java

4
Ravindra babu

l'accès aux valeurs variables variables sera directement à partir de la mémoire principale. Il ne devrait être utilisé que dans un environnement multi-thread. variable statique sera chargé une fois. S'il est utilisé dans un environnement à thread unique, même si la copie de la variable sera mise à jour et qu'il n'y aura aucun problème à 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 on s'attend à ce que le résultat souhaité soit obtenu. Comme chaque thread a sa propre copie, toute augmentation ou diminution d'une variable statique d'un thread peut ne pas être reflétée dans un autre thread.

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

0
Aslam anwer

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 lorsque la mise à jour effectuée par le thread T1 en variable statique, elle a été reflétée dans T2.

0
user2779355