Avant de commencer à vous expliquer le modèle de cache multithread Java, examinons d'abord le morceau de code suivant. La logique de ce code est très simple : le thread principal démarre deux sous-threads, un thread 1 et un thread 2. Le thread 1 s'exécute en premier et le thread 2 s'exécute après avoir dormi pendant 2 secondes. Les deux threads utilisent une variable partagée shareFlag, avec une valeur initiale false. Si shareFlag est toujours égal à false, le thread 1 sera toujours dans une boucle infinie, nous définissons donc shareFlag sur true dans le thread 2.
public class VolatileTest { public static boolean shareFlag = false; public static void main(String[] args) throws InterruptedException { new Thread(() -> { System.out.print("开始执行线程1 =>"); while (!shareFlag){ //shareFlag = false则一直死循环 //System.out.println("shareFlag=" + shareFlag); } System.out.print("线程1执行完成 =>"); }).start(); Thread.sleep(2000); new Thread(() -> { System.out.print("开始执行线程2 =>"); shareFlag = true; System.out.print("线程2执行完成 =>"); }).start(); } }
Si vous n'avez pas appris le modèle de thread JMM, peut-être qu'après avoir lu le code ci-dessus, vous espérez que le résultat de sortie sera le suivant :
Démarrer l'exécution du thread 1 => Démarrer l'exécution du thread 2 => Exécution du thread 2 terminée = > Exécution du thread 1 terminée =>
Comme le montre la figure ci-dessous, les gens normaux comprennent ce code. Tout d'abord, le thread 1 est exécuté pour entrer dans la boucle, le thread 2 modifie shareFlag=true et le thread 1 sort de la boucle. Par conséquent, le thread 1 qui sort de la boucle imprimera "Exécution du thread 1 terminée =>", mais après l'expérience de l'auteur, ** "Exécution du thread 1 terminée =>" ne sera pas imprimé et le thread 1 ne sortira pas de la boucle. la boucle infinie**.
Pour expliquer les problèmes mentionnés ci-dessus, nous devons apprendre le modèle de mémoire Java JMM (Java Memory Model). Je pense qu'il est plus précis de l'appeler modèle de mémoire multithread Java.
Tout d'abord, dans JMM, chaque thread a sa propre mémoire de travail Lorsque le programme démarre, le thread charge (lecture et chargement) les variables partagées dans sa propre mémoire de travail, charge dans la mémoire de travail du thread Variables de mémoire. sont des copies de variables partagées dans la mémoire principale. C'est-à-dire qu'il y a trois copies de shareFlag en mémoire à ce moment-là, et leurs valeurs sont toutes égales à false.
Lorsque le thread 2 exécute shareFlag=true
, il modifie sa copie de mémoire de travail en shareFlag=true
et réécrit simultanément la valeur de la copie (store&write) dans dans la mémoire principale. shareFlag=true
的时候将其工作内存副本修改为shareFlag=true
,同时将副本的值同步写回(store&write)到主内存中。
但是线程1的工作内存中的shareFlag=false
shareFlag=false
3. Protocole de cohérence du cache MESI
La modification des variables partagées par le thread 2 ne sera pas perçue par le thread 1, ce qui est cohérent avec les résultats expérimentaux ci-dessus et le modèle JMM. Alors, comment le thread 1 peut-il percevoir que la valeur de la variable partagée a changé ? En fait, c'est très simple. Ajoutez simplement le mot-clé volatile à la variable partagée shareFlag.public volatile static boolean shareFlag = false;
Si vous ne comprenez pas, vous pouvez l'ignorer. Il sera décrit dans langage simple et exemples ci-dessous. Un instant ).
Modified : Indique que les données de la ligne Cache actuelle sont modifiées (Dirty), et ne sont modifiées que dans le cache du CPU actuel à ce moment, les données de la ligne Cache sont différentes des données ; dans d'autres caches, elles sont également différentes des données en mémoire pour cette ligne.
Exclusif : indique que les données dans la ligne de cache actuelle sont des données valides, et qu'il n'y a pas de ligne de données de ce type dans le cache des autres processeurs et que les données de la ligne de cache actuelle sont les mêmes que les données en mémoire ; .
Partagé : Cela signifie que cette ligne de données sera mise en cache dans le cache de plusieurs processeurs, et les données dans le cache sont cohérentes avec les données dans la mémoire
Invalid : Cela signifie que les données de la ligne de cache actuelle ne sont pas valides ;
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!