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
?
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
.
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.
En plus d’autres réponses, je voudrais ajouter une image à cet effet (la photo est facile à comprendre)
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 .
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.
En termes simples,
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.
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.
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:
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.
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.