question concernant le JMM et la sémantique concernant des champs volatils écrits dans un bloc synchronisé, mais lu non synchronisée.
Dans une version initiale du code ci-dessous, je n'étais pas synchronisée l'accès car il n'était pas nécessaire pour exigences antérieures (et abuser d'une auto-affectation cela.cache = ceci.cache assuré une sémantique volatile volatile). Certaines exigences ont changé, nécessité de la synchronisation afin de garantir que les mises à jour en double ne soient pas envoyées. La question que j'ai est fait que le bloc de synchronisation empêche l'auto-affectation du champ volatiling? P> sans synchronisation, je pense que l'écriture volatile auto-affectation est techniquement nécessaire (bien que L'IDE le drapeau comme n'ayant aucun effet). Avec le bloc synchronisé, je pense qu'il est toujours nécessaire (puisque la lecture est non synchronisée), mais je veux juste confirmer car elle a l'air ridicule dans le code s'il n'est pas réellement requis. Je ne sais pas s'il y a des garanties que je ne suis pas au courant de la fin d'un bloc synchronisé et d'une lecture volatile. P> p>
3 Réponses :
L'auto-affectation veille à ce qu'un autre thread lira la référence de matrice définie et non une autre référence de tableau. Mais vous pourriez avoir un thread en modifiant le tableau pendant qu'un autre fil le lit. P>
Les lectures et les écritures à la matrice doivent être synchronisées. De plus, je ne stockerais pas aveuglément stocker et retourner des tableaux vers / depuis un cache. Un tableau est une structure de données mutable et non threadsafe et tout fil peut corrompre le cache en mutant la matrice. Vous devriez envisager de créer des copies défensives et / ou de renvoyer une liste non modifiable plutôt qu'un tableau d'octets. P>
Merci pour les conseils et je suis d'accord que dans un monde idéal, des copies défensives seraient une bonne chose à faire, mais les matières cachées ici ne seront pas modifiées pour ne pas être modifiée afin que le gain de performance suscitée ne pas faire de copies est préférable (et si Cela change le cache pourrait être enveloppé par une implémentation qui renvoie des copies défensives). Je suis raisonnablement sûr que le code comme écrit est correct, je ne sais tout simplement pas si je peux supprimer l'auto-affectation volatile ou non que j'ai ajouté une synchronisation partielle (par mon commentaire sur une autre réponse, je pense que j'en ai encore besoin, juste vouloir vérifier cela).
+1 Pour la réponse, mais j'ai accepté l'autre réponse puisque elle répond plus directement à la question.
Un indice écrit à un tableau volatil n'a en réalité aucun effet de mémoire. C'est-à-dire que si vous avez déjà instancié la matrice, le champ déclaré que volatile ne vous donnera pas la mémoire sémantique de mémoire que vous recherchez lors de l'attribution d'éléments dans le tableau.
En d'autres termes P>
private final byte[][]cache = ...; cache[row][col] = data;
J'ai eu le même sentiment, mais puisqu'il écrit plus tard à la matrice volatile, et depuis que volatile a un "effet en cascade", sur tout ce qui a été écrit avant l'écriture dans le champ volatil, je pense qu'il n'y a pas de problème de visibilité, en fait. C'est très fragile et serait beaucoup plus clair et robuste avec une getdata synchronisée.
Le problème, cependant, est qu'il n'y a pas eu lieu - avant la relation entre le magasin non volatile et le magasin volatil de cette.cache = ceci.cache
Il en existe un, car l'écriture non volatile à cache [ligne] [COL] est faite avant l'écriture volatile dans le cache, dans le même thread. Et l'écriture volatile se produise - avant la lecture du cache.
Mais puisque l'instance de cache est déjà publiée, d'autres threads peuvent lire cet index du cache après une charge normale et lisez une valeur fade jusqu'à l'écriture volatile
Je comprends qu'il n'y a aucune garantie avec des éléments de réseau volatils, qui est la raison de l'auto-affectation ultérieure. Je crois comprendre que l'auto-affectation volatile garantira que d'autres threads voient la valeur de cache mise à jour (après l'auto-affectation). Je ne suis pas inquiet s'ils voient très temporairement la valeur obsolète. Ma question globale était si j'ai encore besoin de cette auto-affectation avec le bloc synchronisé ou si la fin du bloc synchronisé a une interaction avec des champs volatils, lisez dans le bloc (de votre réponse et de votre propre compréhension, je suppose que non, je voulais juste vérifier ).
Oh je vois quelle est votre question. Eh bien, cette écriture volatile a une sémantique de mémoire similaire comme sortie de moniteur, vous pouvez donc vous débarrasser de la synchronisation. En pratique, toutes ces barrières de mémoire ne feraient pas la différence depuis que vous faites une charge normale. Lorsque vous discutez des effets de mémoire transitifs appliqués par un magasin volatile, il est facile à comprendre avec une comparaison. Par exemple, le cache au cache [col] [ligne] ne sera visible que lorsque
Ma dernière déclaration est plus évidente lorsque vous avez deux champs, int x; volatile int y; x = 10; y = 5; code> après l'écriture sur x = 10 Un thread peut toujours lire x = 0, mais si un fil a lu Y = 5, ils sont garantis pour lire x = 10.
+1 Pour la réponse / commentaires, mais j'ai accepté l'autre réponse puisque elle répond plus directement à la question.
Oui, vous avez toujours besoin de l'écriture volatile, selon le modèle de mémoire Java.
Il n'y a pas de commande de synchronisation de déverrouillage Cependant, les JVM réels ont beaucoup plus de solutions de mémoire. Généralement déverrouiller em> et volatilwrite em> ont l'effet de mémoire même (même s'ils sont sur différentes variables); idem que verrouillage em> et volatileread em>. p> Nous avons donc un dilemme ici. La recommandation typique est que vous devez suivre strictement la spécification. Sauf si vous avez une très large connaissance de la question. Par exemple, un code JDK peut employer des astuces qui ne sont pas théoriquement correctes; Mais le code cible une JVM spécifique et l'auteur est un expert. p> Le surcharge relatif de l'écriture volatile supplémentaire ne semble pas être aussi grande de toute façon. P> Votre code est correct et efficace; Cependant, il est en dehors des schémas typiques; Je le modifierais un peu comme: p> cache code>
à une lecture volatile ultérieure de
cache code>:
Déverrouillage -> volatilheread em> ne garantit pas la visibilité.
Vous avez besoin de déverrouiller -> verrouiller em> ou volatilwrite -> volatileread em>.
Merci pour la réponse, il est clair et confirme ce que je soupçonnais. Les conseils concernant la présence de deux variables de cache sont également une bonne idée, car cela évite d'avoir une personne supprimer l'auto-affectation (malgré l'avertissement de commentaires à ne pas).