La volatilité influence-t-elle les variables non volatiles?

Bon, supposons que j’ai plusieurs variables, dont l’une déclarée volatile:

int a; int b; int c; volatile int v; 

Si un thread écrit dans les quatre variables (écriture dans v last) et qu’un autre thread lit ces quatre variables (en lisant v premier), le second thread voit-il les valeurs écrites dans a , b et c par le premier thread, même bien qu’ils ne soient pas eux-mêmes déclarés volatils? Ou peut-il éventuellement voir des valeurs périmées?

Comme il semble y avoir une certaine confusion: je ne cherche pas délibérément à faire quelque chose de dangereux. Je veux juste comprendre le modèle de mémoire Java et la sémantique du mot clé volatile . Pure curiosité.

Oui. volatile , verrous, etc., configurez la relation happen -before , mais elle affecte toutes les variables (dans le nouveau modèle de mémoire Java (JMM) de Java SE 5 / JDK 1.4). En quelque sorte le rend utile pour les volatiles non primitifs …

Je vais parler de ce que je pense que vous pouvez vraiment explorer: la synchronisation avec le ferroutage .

La technique que vous essayez d’utiliser implique l’utilisation d’une variable volatile en tant que protection de synchronisation, en association avec une ou plusieurs autres variables non volatiles. Cette technique est applicable lorsque les conditions suivantes sont remplies:

  • Un seul thread écrira dans l’ensemble de valeurs censé être gardé.
  • Les threads qui lisent l’ensemble de valeurs ne les liront que si la valeur de garde volatile répond à certains critères.

Vous ne mentionnez pas la deuxième condition qui rest vraie pour votre exemple, mais nous pouvons l’examiner quand même. Le modèle pour l’ auteur est le suivant:

  • Ecrivez dans toutes les variables non volatiles, en supposant qu’aucun autre thread n’essaiera de les lire.
  • Une fois terminé, écrivez dans la variable de garde volatile une valeur indiquant que les critères du lecteur sont satisfaits.

Les lecteurs fonctionnent comme suit:

  • Lisez la variable de garde volatile à tout moment, et si sa valeur répond aux critères, alors
  • Lisez les autres variables non volatiles.

Les lecteurs ne doivent pas lire les autres variables non volatiles si la variable de garde volatile n’indique pas encore une valeur correcte.

La variable de garde agit comme une porte. Il est fermé jusqu’à ce que l’écrivain lui atsortingbue une valeur particulière ou un ensemble de valeurs répondant aux critères indiquant que la porte est maintenant ouverte. Les variables non volatiles sont gardées derrière la porte. Le lecteur n’est pas autorisé à les lire avant que le portail ne s’ouvre. Une fois la porte ouverte, le lecteur obtiendra une vue cohérente de l’ensemble des variables non volatiles.

Notez qu’il n’est pas prudent d’exécuter ce protocole à plusieurs resockets. Le rédacteur ne peut pas continuer à modifier les variables non volatiles une fois la porte ouverte. À ce stade, plusieurs threads de lecture lisent peut-être ces autres variables et peuvent, même si ce n’est pas garanti, voir les mises à jour de ces variables. Le fait de voir certaines de ces mises à jour, mais pas toutes, produirait des vues incohérentes de l’ensemble.

Sauvegarde, le truc ici est de contrôler l’access à un ensemble de variables sans

  • créer une structure pour tous les contenir, à laquelle une référence atomique pourrait être échangé, um, atomiquement, ou
  • utiliser un verrou pour écrire et lire sur l’ensemble des variables des activités mutuellement exclusives.

Piggybacking au-dessus de la variable de garde volatile est une cascade intelligente – ne doit pas être faite avec désinvolture. Les mises à jour ultérieures du programme peuvent mettre fin aux conditions précitées précitées en supprimant les garanties de cohérence offertes par le modèle de mémoire Java. Si vous choisissez d’utiliser cette technique, documentez clairement ses invariants et ses exigences dans le code.

ce second thread voit-il les valeurs écrites en a, b et c par le premier thread, même si elles ne sont pas elles-mêmes déclarées volatiles? Ou peut-il éventuellement voir des valeurs périmées?

Vous obtiendrez des lectures périmées, b / c vous ne pouvez pas vous assurer que les valeurs de a, b, c sont celles définies après la lecture de v. Utiliser la machine à états (mais vous avez besoin de CAS pour changer l’état) est un moyen de lutter questions similaires, mais cela dépasse le cadre de la discussion.

Peut-être que cette partie n’est pas claire. Après avoir écrit dans v et lu tout d’abord v , vous obtiendrez les bons résultats (lectures non périmées). Le problème principal est que si vous le faites if (v==STATE1){...proceed...} , il n’y a aucune garantie qu’un autre thread ne modifie pas l’état de a / b / c. Dans ce cas, il y aura des lectures d’état. Si vous modifiez le a / b / c + v une fois seulement, vous obtiendrez le résultat correct.

Maîsortingser la concurrence et les structures sans locking est une tâche vraiment difficile. Doug Lea a un bon livre et la plupart des conférences / articles de Dr. Cliff Click sont une richesse merveilleuse, si vous avez besoin de quelque chose pour commencer à creuser.

Oui, écriture volatile “arrive-avant” prochaine lecture volatile sur la même variable.

Bien que @seh ait raison sur les problèmes de cohérence liés à plusieurs variables, il existe des cas d’utilisation nécessitant moins de cohérence.

Par exemple, un thread d’écriture met à jour certaines variables d’état; un fil de lecture les affiche rapidement. Il n’ya pas beaucoup de relation entre les variables, nous ne nous soucions que de lire rapidement les nouvelles valeurs. Nous pourrions rendre chaque variable d’état volatile. Ou nous pourrions utiliser une seule variable volatile comme protection de visibilité.

Cependant , les économies ne se font que sur le papier. En termes de performances, il n’ya guère de différence. Dans les deux versions, chaque variable d’état doit être “purgée” par le rédacteur et “chargée” par le lecteur. Pas de repas gratuit.