Différences : 1. La volatilité ne provoquera pas de blocage du fil ; la synchronisation peut provoquer un blocage du fil. 2. Volatile garantit la visibilité des données, mais ne peut pas garantir l'atomicité, tandis que la synchronisation peut garantir l'atomicité et indirectement garantir la visibilité.
Visibilité
Visibilité : Une paire de threads Après une variable partagée est modifiée, les autres threads peuvent immédiatement voir (percevoir) la modification (changement) de la variable.
Le modèle de mémoire Java synchronise les valeurs modifiées des variables dans la mémoire de travail avec la mémoire principale et actualise les dernières valeurs de la mémoire principale vers la mémoire de travail avant de lire les variables. sur la mémoire principale pour obtenir de la visibilité.
Atomicité (Atomicité)
Atomicité : Une opération ne peut pas être interrompue, soit elle est entièrement exécutée, soit elle ne l'est pas exécuté.
Ce que garantit le modèle de mémoire Java, c'est que toutes les opérations au sein du même thread se font de haut en bas. Cependant, lorsque plusieurs threads s'exécutent en parallèle, l'ordre de leurs opérations ne peut pas être garanti.
Ordre
Ordre : Observez dans ce fil, les opérations sont toutes dans l'ordre si dans un Lorsque vous observez un autre fil dans ; un fil, toutes les opérations sont dans le désordre.
Ce que garantit le modèle de mémoire Java, c'est que toutes les opérations au sein du même thread se font de haut en bas. Cependant, lorsque plusieurs threads s'exécutent en parallèle, l'ordre de leurs opérations ne peut pas être garanti.
Lorsque l'ordinateur exécute un programme, afin d'améliorer les performances, le compilateur et le processeur réorganisent souvent les instructions , qui sont généralement divisées en trois types suivants
Unique -environnement threadé Il garantit que le résultat final de l'exécution du programme est cohérent avec le résultat de l'exécution du code
Le processeur doit prendre en compte les dépendances de données entre les instructions lors de la réorganisation
Dans un environnement multithread Dans l'environnement, les threads s'exécutent alternativement. En raison de l'existence d'un réarrangement d'optimisation du compilateur, il n'est pas certain que les variables utilisées dans les deux threads puissent assurer la cohérence des variables utilisées, et les résultats sont imprévisibles
Faites ce que vous pouvez faire dans le examen d'abord, et faites ce que vous ne pouvez pas faire plus tard.
public void mySort(){ int x = 11; //1 int y = 12; //2 x= x+5; // 3 y = x*x;//4
Ordre possible 1234 2134 1324, attribut 4 impossible avant 1 et 3, à cause de la dépendance des données.
volatile interdit la réorganisation des instructions.
public class ReSortSeqDemo { int a = 0; boolean flag = false; public void method01() { a = 1; // flag = true; // ----线程切换---- flag = true; // a = 1; } public void method02() { if (flag) { a = a + 3; System.out.println("a = " + a); } } }
Si deux threads sont exécutés en même temps, la méthode01 et la méthode02 sont réorganisées si le thread 1 exécute la méthode01, puis le thread commuté 2 exécute la méthode02, il y aura des résultats différents.
Désactiver la réorganisation des instructions
volatile réalise l'optimisation de la désactivation de la réorganisation des instructions, évitant ainsi le phénomène de désordre du programme dans un environnement multithread
Comprenez d'abord un concept. La barrière mémoire, également connue sous le nom de barrière mémoire, est une instruction CPU. Elle a deux fonctions :
Garantir l'ordre d'exécution d'opérations spécifiques
Assurer qu'une certaine mémoire. visibilité de certaines variables (utilisez cette fonctionnalité pour obtenir une visibilité de la mémoire volatile)
Étant donné que le compilateur et chaque processeur peuvent effectuer une optimisation de la réorganisation des instructions, si une barrière de mémoire est insérée entre les instructions, elle le dira au compilateur et au processeur, aucune instruction ne peut réorganiser cette instruction Memory Barrier, ce qui signifie que la réorganisation de l'optimisation avant et après la barrière mémoire est interdite par l'insertion d'une barrière mémoire. Une autre fonction de la barrière mémoire est de forcer le vidage de diverses données du cache du processeur, afin que n'importe quel thread du processeur puisse lire la dernière version de ces données.
Ce qui suit est un diagramme schématique de la séquence d'instructions générée après l'insertion d'une écriture volatile dans la barrière mémoire selon la stratégie conservatrice :
Ce qui suit est la séquence d'instructions générée après une lecture volatile est inséré dans la barrière mémoire sous la stratégie conservatrice Schéma schématique :
Garantie de sécurité des threads
Le délai de synchronisation entre la mémoire de travail et la mémoire principale provoquent des problèmes de visibilité
Peuvent être résolus à l'aide de mots-clés synchronisés ou volatiles, qui peuvent utiliser des variables modifiées par un thread pour être immédiatement visibles par les autres threads
Pour les problèmes de visibilité et les problèmes d'ordre causés par le réarrangement des instructions
peut être résolu en utilisant le mot clé volatile, car une autre fonction de volatile est d'interdire l'optimisation de la réorganisation des instructions
volatile
le variable qu'elle modifieNe pas en conserver de copie, accéder directement à la mémoire principale .
Dans le modèle de mémoire Java, il y a mémoire principale, et chaque thread possède également sa propre mémoire (comme des registres). Pour des raisons de performances, un thread conserve une copie des variables auxquelles il accède dans sa propre mémoire. De cette façon, il y aura des situations où la valeur de la même variable dans la mémoire d'un thread peut être incohérente avec la valeur dans la mémoire d'un autre thread ou avec la valeur dans la mémoire principale à un certain moment. Déclarer une variable comme volatile signifie que la variable peut être modifiée par d'autres threads à tout moment, elle ne peut donc pas être mise en cache dans la mémoire des threads.
Scénarios d'utilisation
Vous ne pouvez utiliser des variables volatiles pour remplacer les verrous que dans des situations limitées. Pour que les variables volatiles offrent une sécurité idéale des threads, les deux conditions suivantes doivent être remplies en même temps :
1) L'opération d'écriture dans la variable ne dépend pas de la valeur actuelle.
2) La variable n'est pas incluse dans un invariant avec d'autres variables.
volatile est le plus approprié pour les situations où un thread écrit et plusieurs threads lisent.
Si plusieurs threads écrivent simultanément, vous devez toujours utiliser des verrous, des conteneurs thread-safe ou des variables atomiques à la place.
synchronisé
Lorsqu'il est utilisé pour modifier une méthode ou un bloc de code , il peut assurer Au plus un thread peut exécuter ce code en même temps .
Lock
À partir de jdk 5.0, Java fournit un mécanisme de synchronisation de threads plus puissant - la synchronisation est obtenue en définissant explicitement les objets de verrouillage de synchronisation, et les verrous de synchronisation sont L'objet de verrouillage utilisé agit comme.
L'interface java.util.concurrent.Locks.Lock est un outil permettant de contrôler l'accès de plusieurs threads aux ressources partagées. Les verrous fournissent un accès exclusif aux ressources partagées. Un seul thread à la fois peut verrouiller l'objet Lock. Le thread doit obtenir l'objet Lock avant de commencer à accéder aux ressources partagées.
La classe ReentrantLock implémente Lock, qui a la même concurrence et la même sémantique de mémoire que synchronisée. Pour réaliser le contrôle de la sécurité des threads, ReentrantLock est plus couramment utilisé et peut afficher les verrous et les libérer.
Différence
volatile et synchronisée
volatile est un modificateur de variable, tandis que synchronisé agit sur un morceau de code ou une méthode .
volatile synchronise simplement la valeur d'une variable entre la mémoire du thread et la mémoire "principale" ; tandis que synchronisé synchronise la valeur de toutes les variables en verrouillant et déverrouillant un moniteur, évidemment synchronisé vaut mieux que volatile consomme plus de ressources.
volatile ne provoquera pas de blocage des threads ; synchronisé peut provoquer un blocage des threads.
volatile garantit la visibilité des données, mais ne peut pas garantir l'atomicité tandis que synchronisé peut garantir l'atomicité et indirectement garantir la visibilité, car il le fera. synchroniser les données dans la mémoire privée et la mémoire publique.
Les variables marquées comme volatiles ne seront pas optimisées par le compilateur ; les variables marquées comme synchronisées peuvent être optimisées par le compilateur.
La sécurité des threads comprend deux aspects : l'atomicité et la visibilité. Le mécanisme de synchronisation de Java se concentre sur ces deux aspects pour garantir la sécurité des threads.
Le mot-clé volatile est principalement utilisé lorsque plusieurs threads peuvent détecter que des variables d'instance ont été modifiées et peuvent obtenir la dernière valeur. Autrement dit, lorsque plusieurs threads lisent des variables partagées, ils peuvent obtenir la dernière valeur.
Le mot clé volatile invite le thread à lire à chaque fois les variables de la mémoire partagée au lieu de lire depuis la mémoire privée, assurant ainsi la visibilité des données synchronisées. Mais attention : si vous modifiez les données dans la variable d'instance
Par exemple : i++, c'est-à-dire i=i+1, alors une telle opération n'est pas réellement une opération atomique, c'est-à-dire qu'elle n'est pas thread-safe. Les étapes de fonctionnement de l'expression i++ se décomposent comme suit :
1) Récupérer la valeur de i en mémoire.
2) Calculez la valeur de i;
3) Écrivez la valeur de i en mémoire.
Si un autre thread modifie également la valeur de i lors du calcul de la valeur à l'étape 2, les données de lecture sales apparaîtront dans le nom à ce moment-là. La solution consiste à utiliser le mot-clé synchronisé. So volatile lui-même ne gère pas l'atomicité des données, mais force la lecture et l'écriture des données à affecter la mémoire principale en temps opportun.
synchronisé et verrouillé
Le verrouillage est un verrouillage d'affichage (ouverture et fermeture manuelles, n'oubliez pas d'éteindre le verrouillage), synchronisé est un implicite Verrouillage, hors de portée Libérez automatiquement le verrou.
Le verrouillage verrouille uniquement les blocs de code, synchronisé peut agir sur les blocs de code et les méthodes.
Grâce à Lock, la JVM passe moins de temps à planifier les threads et fonctionne mieux. Et a une meilleure évolutivité (offrant plus de sous-classes).
Séquence d'utilisation : Verrouiller-> bloc de code synchronisé (est entré dans le corps de la méthode et a alloué les ressources correspondantes) ->
Pour plus de connaissances liées à la programmation, veuillez visiter : Cours d'apprentissage en programmation ! !
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!