Maison >Java >javaDidacticiel >Quels sont les modèles de mémoire volatile et Java de la haute concurrence Java ?
public class Demo09 { public static boolean flag = true; public static class T1 extends Thread { public T1(String name) { super(name); } @Override public void run() { System.out.println("线程" + this.getName() + " in"); while (flag) { ; } System.out.println("线程" + this.getName() + "停止了"); } } public static void main(String[] args) throws InterruptedException { new T1("t1").start(); //休眠1秒 Thread.sleep(1000); //将flag置为false flag = false; } }
Exécutez le code ci-dessus et vous constaterez que le programme ne peut pas être terminé.
Il y a une boucle dans la méthode run() du thread t1. Le drapeau est utilisé pour contrôler si la boucle se termine. Le thread principal dort pendant 1 seconde et définit le drapeau sur false. t1 détectera que l'indicateur est faux et affichera " Thread t1 arrêté", pourquoi le résultat est-il différent de ce à quoi nous nous attendions ? En exécutant le code ci-dessus, nous pouvons juger que l'indicateur vu dans t1 est toujours vrai. Une fois que le thread principal a défini l'indicateur sur false, il n'est pas vu dans le thread t1, il continue donc à boucler.
Alors pourquoi ne puis-je pas voir le drapeau modifié par le fil de discussion principal dans t1 ?
Pour expliquer cela, nous devons d'abord comprendre le modèle de mémoire Java (JMM). La communication entre les threads Java est contrôlée par le modèle de mémoire Java (appelé JMM dans cet article). La variable doit être écrite dans un autre thread. Un thread est visible. D'un point de vue abstrait, JMM définit la relation abstraite entre les threads et la mémoire principale : les variables partagées entre les threads sont stockées dans la mémoire principale (mémoire principale), et chaque thread possède une mémoire locale privée (mémoire locale), une copie de la mémoire partagée. La variable que le thread lit/écrit est stockée dans la mémoire locale. La mémoire locale est un concept abstrait de JMM et n'existe pas vraiment. Il couvre les caches, les tampons d'écriture, les registres et d'autres optimisations du matériel et du compilateur. Le diagramme schématique abstrait du modèle de mémoire Java est le suivant :
Comme le montre la figure ci-dessus, le thread A doit communiquer avec le thread B et doit passer par les 2 étapes suivantes :
1. le thread A stocke la mémoire locale A dans Les variables partagées mises à jour sont vidées dans la mémoire principale
2 Ensuite, le thread B va dans la mémoire principale pour lire les variables partagées que le thread A a précédemment mises à jour
Ce qui suit est un diagramme schématique. illustrez ces deux étapes :
Comme le montre la figure ci-dessus, les mémoires locales A et B ont des copies de la variable partagée x dans la mémoire principale. Supposons qu'au départ, les valeurs x dans ces trois mémoires soient toutes 0. Lorsque le thread A est en cours d'exécution, il stocke temporairement la valeur x mise à jour (en supposant que la valeur est 1) dans sa propre mémoire locale A. Lorsque le thread A et le thread B doivent communiquer, le thread A actualise d'abord la valeur x modifiée dans sa mémoire locale dans la mémoire principale. À ce moment, la valeur x dans la mémoire principale devient 1. Par la suite, le thread B accède à la mémoire principale pour lire la valeur x mise à jour du thread A. À ce stade, la valeur x de la mémoire locale du thread B devient également 1. Globalement, ces deux étapes consistent essentiellement pour le thread A à envoyer des messages au thread B, et ce processus de communication doit passer par la mémoire principale. JMM offre aux programmeurs Java des garanties de visibilité de la mémoire en contrôlant l'interaction entre la mémoire principale et la mémoire locale de chaque thread.
Après avoir compris JMM, regardons la question au début de l'article. Pourquoi ne pouvons-nous pas voir la valeur du drapeau qui a été modifié en false par le fil principal du fil t1 :
1 ? .Une fois que le thread principal a modifié le drapeau, il n'est pas actualisé dans la mémoire principale, donc t1 ne peut pas le voir
2 Le thread principal actualise le drapeau dans la mémoire principale, mais t1 continue de lire la valeur du drapeau dans sa propre. mémoire de travail et ne va pas dans la mémoire principale pour obtenir la dernière valeur du drapeau
Pour les deux situations ci-dessus, existe-t-il un moyen de le résoudre ?
Existe-t-il une telle méthode : une fois que le thread a modifié la copie dans la mémoire de travail, elle est immédiatement actualisée dans la mémoire principale à chaque fois que la variable partagée est lue dans la mémoire de travail, elle est relue dans la mémoire principale ; , puis Copier dans la mémoire de travail.
Java nous fournit une telle méthode. Utiliser volatile pour modifier des variables partagées peut obtenir l'effet ci-dessus. Les variables modifiées par volatile ont les caractéristiques suivantes :
1. la mémoire principale pour lire la dernière valeur de la variable partagée, puis la copier dans la mémoire de travail
2. Le thread modifie la copie de la variable dans la mémoire de travail. Après la modification, elle sera immédiatement actualisée dans la mémoire principale. mémoire
Modifions le début Exemple de code :
public volatile static boolean flag = true;
Utilisez volatile pour modifier la variable flag, puis exécutez le programme. Le résultat est :
线程t1 in 线程t1停止了
Le programme peut maintenant s'arrêter normalement. Volatile résout le problème de visibilité des variables partagées dans les multi-threads. La visibilité fait référence à la question de savoir si la modification des variables partagées par un thread est visible par un autre thread.
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!