web-dev-qa-db-fra.com

Réorganisation des instructions et relation passe-avant dans java

Dans le livre Java Concurrency In Practice, on nous dit plusieurs fois que les instructions de notre programme peuvent être réorganisées, soit par le compilateur, par la JVM lors de l'exécution, soit même par le processeur. Donc nous devons supposer que le programme exécuté n'aura pas ses instructions exécutées exactement dans le même ordre que ce que nous avons spécifié dans le code source.

Cependant, le dernier chapitre traitant de Java Memory Model fournit une liste des règles occur-before indiquant l'ordre des instructions qui sont préservées par la JVM. La première de ces règles est:

  • "Règle d'ordre de programme. Chaque action d'un thread se produit avant chaque action de ce thread qui vient plus tard dans l'ordre du programme."

Je crois que "l'ordre des programmes" fait référence au code source.

Ma question: en supposant cette règle, je me demande quelle instruction peut être réorganisée.

"Action" est définie comme suit:

Le modèle de mémoire Java Java est spécifié en termes d’actions, qui incluent les lectures et les écritures sur les variables, les verrous et les déverrouillages des moniteurs, ainsi que le démarrage et la jonction avec des threads. Le JMM définit un ordre partiel appelé se produit avant sur toutes les actions du programme. Pour garantir que le thread exécutant l'action B puisse voir les résultats de l'action A (que A et B se produisent ou non dans différents threads), il doit y avoir un événement avant la relation entre A et B. En l'absence d'un événement avant de passer une commande entre deux opérations, la JVM est libre de les réorganiser à sa guise.

Les autres règles de commande mentionnées sont:

  • Surveiller la règle de verrouillage. Un déverrouillage sur un verrou de moniteur se produit avant chaque verrou suivant sur ce même verrou de moniteur.
  • Règle de variable volatile. Une écriture dans un champ volatile se produit avant chaque lecture ultérieure de ce même champ.
  • Règle de début de thread. Un appel à Thread.start sur un thread se produit avant chaque action dans le thread démarré.
  • Règle de terminaison de thread. Toute action dans un thread se produit avant qu'un autre thread ne détecte que ce thread s'est terminé, soit en revenant avec succès de Thread.join, soit en renvoyant false par Thread.isAlive.
  • Règle d'interruption. Un thread appelant une interruption sur un autre thread se produit avant que le thread interrompu ne détecte l'interruption (soit en faisant lever InterruptedException, soit en invoquant isInterrupted ou interrompu).
  • Règle du finaliseur. La fin d'un constructeur pour un objet se produit avant le début du finaliseur pour cet objet.
  • Transitivité. Si A se produit avant B et B se produit avant C, alors A se produit avant C.
53
Martin

Le point clé de la règle d'ordre du programme est: dans un fil.

Imaginez ce programme simple (toutes les variables initialement 0):

T1:

x = 5;
y = 6;

T2:

if (y == 6) System.out.println(x);

Du point de vue de T1, une exécution doit être cohérente avec l'affectation de y après x (ordre du programme). Cependant, du point de vue de T2, cela ne doit pas être le cas et T2 peut imprimer 0.

T1 est en fait autorisé à assigner y en premier car les 2 affectations sont indépendantes et leur permutation n'affecte pas l'exécution de T1.

Avec une synchronisation appropriée, T2 imprimera toujours 5 ou rien.

[~ # ~] modifier [~ # ~]

Vous semblez mal interpréter le sens de l'ordre des programmes. La règle d'ordre du programme se résume à :

Si x et y sont des actions du même thread et que x précède y dans l'ordre du programme, alors hb(x, y) (ie x arrive-avanty).

arrive-avant a une signification très spécifique dans le JMM. En particulier, cela signifie pas signifie que y=6 Doit être postérieur à x=5 En T1 du point de vue de l'horloge murale. Cela signifie seulement que la séquence d'actions exécutées par T1 doit être cohérente avec cet ordre. Vous pouvez également vous référer à JLS 17.4.5 :

Il est à noter que la présence d'une relation passe-avant entre deux actions n'implique pas nécessairement qu'elles doivent se dérouler dans cet ordre dans une implémentation . Si la réorganisation produit des résultats compatibles avec une exécution légale, elle n'est pas illégale.

Dans l'exemple que j'ai donné ci-dessus, vous conviendrez que du point de vue de T1 (c'est-à-dire dans un programme à thread unique), x=5;y=6; Est cohérent avec y=6;x=5; Puisque vous ne lisez pas les valeurs. Une déclaration sur la ligne suivante est garantie, en T1, pour voir ces 2 actions, quel que soit l'ordre dans lequel elles ont été effectuées.

55
assylias