Maison  >  Article  >  Java  >  [Lutte contre la concurrence Java]-----Réorganisation du modèle de mémoire Java

[Lutte contre la concurrence Java]-----Réorganisation du modèle de mémoire Java

黄舟
黄舟original
2017-02-24 10:05:261198parcourir

Lors de l'exécution d'un programme, afin d'améliorer les performances, les processeurs et les compilateurs réorganisent souvent les instructions, mais elles ne peuvent pas être réorganisées à volonté. Vous ne pouvez pas les trier comme vous le souhaitez. Il doit remplir les deux conditions suivantes :

1. Les résultats de l'exécution du programme ne peuvent pas être modifiés dans un environnement monothread ;

2. La réorganisation n'est pas autorisée s'il existe des dépendances de données

Si vous avez lu le précédent de LZ. blog, Vous saurez qu'en fait, ces deux points peuvent être attribués à une chose : cela ne peut pas être déduit par le principe qui se produit avant, et JMM permet un ordre arbitraire.

sémantique comme si-série

la sémantique comme si-série signifie que toutes les opérations peuvent être réorganisées pour l'optimisation, mais vous devez vous assurer qu'elles sont exécutées après la réorganisation. Le résultat ne peut pas être modifié, et le compilateur, le moteur d'exécution et le processeur doivent adhérer à la sémantique comme si c'était une série. Notez que as-if-serial garantit uniquement un environnement monothread et n'est pas valide dans un environnement multithread.

Utilisons un exemple simple pour illustrer :

int a = 1 ;      //A
int b = 2 ;      //B
int c = a + b;   //C
Les trois opérations de A, B et C ont la relation suivante : A et B n'ont pas de dépendances de données. , Il existe une relation de dépendance des données entre B et C, donc lors de la réorganisation, A et B peuvent être triés arbitrairement, mais ils doivent être devant C. L'ordre d'exécution peut être A –> > A – > C. Mais quel que soit l’ordre d’exécution, le résultat final C est toujours égal à 3.

la sémantique comme si serail protège les programmes monothread, ce qui peut garantir que le résultat final du programme est toujours cohérent dans le cadre d'une réorganisation.

En fait, pour le code ci-dessus, ils ont une telle relation qui se produit avant :

  1. A se produit avant B

  2. B arrive avant C

  3. A arrive avant C

1 et 2 sont des règles de séquence de programme, et 3 est la transitivité. Cependant, cela ne signifie-t-il pas que grâce à la réorganisation, B peut être exécuté avant A ? Pourquoi A se produit-il avant B ? Ici encore, il est indiqué que A se produit avant B, ce n'est pas que A sera définitivement exécuté avant B, mais que A est visible par B, mais par rapport à ce programme, les résultats de l'exécution de A n'ont pas besoin d'être visibles par B, et leur réorganisation n'affectera pas les résultats. JMM ne considérera donc pas cette réorganisation comme illégale.

Nous devons comprendre cela : améliorer autant que possible l'efficacité opérationnelle du programme sans modifier les résultats d'exécution du programme.

Ci-dessous, nous examinons un morceau de code intéressant :

public class RecordExample1 {
    public static void main(String[] args){        
    int a = 1;        
    int b = 2;        
    try {
            a = 3;           //A
            b = 1 / 0;       //B
        } catch (Exception e) {

        } finally {
            System.out.println("a = " + a);
        }
    }
}
Selon les règles de réorganisation, l'opération A et l'opération B peuvent être réorganisées si elles sont réorganisées, B lancera An. une exception se produit (/ par zéro). À ce moment, l'instruction A ne sera certainement pas exécutée. Alors a sera-t-il toujours égal à 3 ? Si vous suivez le principe comme en série, cela change le résultat du programme. En fait, la JVM effectue un traitement spécial pour les exceptions. Afin de garantir une sémantique comme si c'était une série, le mécanisme de gestion des exceptions Java effectue un traitement spécial pour la réorganisation : JIT insérera une compensation d'erreur dans l'instruction catch lors de la réorganisation. = 3), bien que cela complique la logique de cathc, le principe d'optimisation JIT est le suivant : optimiser autant que possible la logique dans le cadre du fonctionnement normal du programme, même au détriment de la complexité de la logique du bloc catch.

L'impact de la réorganisation sur le multi-threading

Dans un environnement monothread en raison de la sémantique comme si elle était en série, la réorganisation ne peut pas affecter le résultat final, mais qu'en est-il d'un environnement multithread ?

Le code suivant (utilisation classique de volatile) :

public class RecordExample2 {
    int a = 0;    boolean flag = false;    
    /**
     * A线程执行
     */
    public void writer(){
        a = 1;                  
        // 1
        flag = true;            
        // 2
    }    /**
     * B线程执行
     */
    public void read(){        
    if(flag){                  
    // 3
           int i = a + a;          
           // 4
        }
    }

}
Le thread A exécutewriter(), le thread B exécute read(), le thread B peut-il lire a = 1 pendant l'exécution de Woolen ? tissu? La réponse n'est pas nécessairement (

Remarque : le processeur X86 ne prend pas en charge la réorganisation en écriture-écriture. S'il fonctionne sur x86, ce sera certainement a=1. LZ ne l'a pas testé depuis longtemps et a finalement découvert après avoir vérifié les informations ).

Comme il n'y a pas de dépendance de données entre l'opération 1 et l'opération 2, la réorganisation peut être effectuée. Il n'y a pas de dépendance de données entre l'opération 3 et l'opération 4. Elles peuvent également être réorganisées, mais les opérations 3 et 4 ont une dépendance. contrôler la dépendance entre les opérations 4. Si l'opération 1 et l'opération 2 sont réordonnées :

[Lutte contre la concurrence Java]-----Réorganisation du modèle de mémoire Java

Selon cet ordre d'exécution, le thread B ne pourra certainement pas lire la valeur a définie par le thread A. La sémantique de multi-threading voici Il a été détruit par la réorganisation.

L'opération 3 et l'opération 4 peuvent également être réorganisées, ce qui ne sera pas expliqué ici. Mais il existe une relation de dépendance de contrôle entre eux, car l’opération 4 ne sera exécutée que si l’opération 3 est établie. Lorsque des dépendances de contrôle existent dans le code, cela affectera le parallélisme de l'exécution de la séquence d'instructions, de sorte que les compilateurs et les processeurs utiliseront l'exécution par devinette pour surmonter l'impact des dépendances de contrôle sur le parallélisme. Si l'opération 3 et l'opération 4 sont réorganisées et que l'opération 4 est exécutée en premier, le résultat du calcul sera temporairement enregistré dans le tampon de réorganisation. Lorsque l'opération 3 est vraie, le résultat du calcul sera écrit dans la variable i

via le. Dans l'analyse ci-dessus,

la réorganisation n'affectera pas les résultats d'exécution d'un environnement monothread, mais détruira la sémantique d'exécution des multi-threads .

Ce qui précède est le contenu de [Java Concurrency] -----Réorganisation du modèle de mémoire Java Pour plus de contenu connexe, veuillez faire attention au site Web PHP chinois (www.php.cn) !



Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn