6
votes

Un cas d'utilisation pour synchronisé (nouvel objet ())

dans une récente Réponse J'ai suggéré qu'il soit possible d'atteindre la fonctionnalité de volatile Par Synchronisation sur l'objet contenant la variable, nous devons être volatile (Acheter n'a pas accès à la variable dans le code).

Cela m'a fait penser que je n'ai pas besoin de bloquer sur l'objet contenant, j'ai juste besoin d'obtenir une barrière de mémoire. Comme synchronisé atteint la synchronisation et une barrière mémoire, si tout ce dont j'ai besoin est la barrière mémoire (comme dans ce cas) serait-elle réellement meilleure Pour utiliser synchronisé (nouvel objet ()) pour atteindre ma barrière de mémoire et Assurez-vous que la serrure n'est jamais affirmée?


3 Réponses :


2
votes

serait-il vraiment préférable d'utiliser synchronisé (nouvel objet ()) pour atteindre mon barrière de mémoire et assurez-vous que le verrou n'est jamais allégé?

nop. Le JVM peut facilement prouver que ce verrouillage ne peut pas être accessible par deux threads (puisqu'il s'agit d'une variable de thread-locale) et de la transformer presque certainement en un non-op, c'est-à-dire complètement supprimer le synchronisé déclaration.


2 commentaires

Alors, comment puis-je obtenir une barrière de mémoire comme volatile sans régler la variable réelle volatile tout en minimisant / éliminant la conflit de verrouillage?


@OldcurMudgeon j'ai vu quelque chose dans le paquet Sun.Misc, mais pas sûr si c'était dans JDK 7 ou 8 (quelque chose comme: non sécurisé.load / non sécurisé.store) - ne peut pas la creuser maintenant.



3
votes

Comme expliqué ici: http: / /www.cs.umd.edu/~pugh/java/MemoryModel/jsr-133-faq.html#synchronisation Synchronisé (nouvel objet ()) est considéré comme un noop et peut être entièrement supprimé par le compilateur. Vous n'obtiendrez pas de barrière de mémoire.


1 commentaires

Qu'est-ce qui réaliserait ce que j'essaie d'obtenir - une barrière de mémoire sans lutter contre la serrure?



2
votes

En plus du très bon point de @ Assylias, considérons également que synchronisé n'atteint pas une barrière de mémoire par des spécifications. Ce n'est que le cas où il s'agit de la manière dont il est mis en œuvre sur les architectures typiques de la mémoire CPU d'aujourd'hui. La spécification ne garantit que ce qui se passe lorsque deux threads acquièrent le même verrou.

Quoi qu'il en soit, si vous vous souciez de la spécification, mais uniquement sur les implémentations du monde réel, alors pourquoi ne pas introduire votre propre variable volatile et simplement écrivez-y quand vous voulez une barrière de mémoire ? C'est sans importance quel volatile vous écrivez, tant que nous parlons d'un ensemble d'architectures contraint qui est impliqué par votre synchronisé (nouvel objet () ) idée.


7 commentaires

Je pense que c'est le point critique que je manque - la barrière ne s'applique qu'à tous les partampis de l'objet de verrouillage spécifique. Bien que la plupart des discussions sur ce sujet mentionnent des caches de rinçage, il serait tout à fait possible pour une implémentation de simplement pousser les valeurs mises en cache d'un processeur à une autre.


Dans la question, Asker voulait appeler un Set ... méthode d'un objet qu'ils ne disposent pas de contrôle de plusieurs threads. La variable ne peut pas être faite volatile .


Oui, je m'attends à ce que cela se produise comme le nombre d'unités d'exécution (cœurs ou autre) grandit. Dans des systèmes massivement parallèles, il n'y a pas de cohérence cache, et je pense que le grand public est fermement installé sur cette route maintenant.


Malheureusement, il n'y a pas de primitive Java qui a la sémantique exacte de la "barrière mémoire".


Après votre modification - suggérez-vous que l'accès à une variable volatile toute invalidera les valeurs mises en cache toutes ? J'aurais pensé que que la variable serait rinçue dans ce cas.


Ce n'est certainement pas seulement celui-là, et c'est par spécification: tout accessible de ce VaR (si elle est dactylographiée, bien sûr) doit également être rinçue. C'était un motivateur clé de la grande réécriture du modèle de mémoire Java pour Java 1.5.


Pardonnez-moi, je pense que c'est en fait toutes les actions du fil qui a fait l'écriture sont visibles au fil qui fait la lecture --- qui est très proche d'une barrière de mémoire réelle!