127 votes

AtomicInteger lazySet vs. set

Quelle est la différence entre le lazySet y set méthodes de AtomicInteger ? Le site documentation n'a pas grand-chose à dire sur lazySet :

Définit éventuellement la valeur donnée.

Il semble que la valeur stockée ne sera pas immédiatement réglée sur la valeur souhaitée, mais qu'elle sera programmée pour être réglée à un moment donné dans le futur. Mais, quelle est l'utilisation pratique de cette méthode ? Un exemple ?

119voto

yawn Points 2823

Cité directement dans "JDK-6275329 : Ajouter les méthodes lazySet aux classes atomiques" :

Comme probablement le dernier petit suivi de JSR166 pour Mustang, nous avons ajouté une méthode "lazySet" aux classes Atomic (AtomicInteger, AtomicReference, etc). Il s'agit d'une méthode de niche qui est parfois utile lors de la mise au point du code en utilisant structures de données non-bloquantes. La sémantique est la suivante sémantique est que l'écriture est garantie de ne pas être réordonnée avec les précédente, mais qu'elle peut être réordonnée avec les opérations suivantes (ou de manière équivalente, peut ne pas être visible pour les autres threads) jusqu'à ce que une autre écriture volatile ou une action de synchronisation se produise).

Le principal cas d'utilisation est l'annulation des champs des nœuds dans les fichiers dans des structures de données non bloquantes dans le seul but d'éviter une d'éviter la rétention à long terme des ordures ; cela s'applique lorsque c'est inoffensif. si d'autres threads voient des valeurs non nulles pendant un certain temps, mais vous mais que vous voulez vous assurer que les structures sont finalement GCables. Dans un tel Dans de tels cas, vous pouvez obtenir de meilleures performances en évitant les coûts de l'écriture volatile des valeurs nulles. Il existe quelques quelques autres cas d'utilisation de ce type pour les atomiques non référencés, de sorte que la méthode est prise en charge par tous les types d classes AtomicX.

Pour les personnes qui aiment penser à ces opérations en termes de barrières au niveau de la machine sur les multiprocesseurs courants, lazySet fournit une barrière store-store précédente (ce qui est soit ou très bon marché sur les plateformes actuelles), mais pas de barrière de barrière store-load (qui est généralement la partie coûteuse d'une écriture volatile).

18 votes

Quelqu'un pourrait-il l'expliquer pour le reste d'entre nous ? :(

15 votes

Lazy est la version non-volatile (par exemple, le changement d'état n'est pas garanti d'être visible pour tous les threads qui ont l'attribut Atomic* dans le champ d'application).

68 votes

Ce que je ne comprends pas, c'est pourquoi la javadoc est si pauvre à ce sujet.

18voto

porkchop Points 99

LazySet peut être utilisé pour la communication inter-filière rmw, parce que xchg est atomique, comme pour la visibilité, lorsque le processus du fil d'écriture modifie l'emplacement d'une ligne de cache, le processeur du fil de lecture le verra à la prochaine lecture, parce que le protocole de cohérence de cache du processeur intel garantira que LazySet fonctionne, mais la ligne de cache sera mise à jour à la prochaine lecture, encore une fois, le processeur doit être suffisamment moderne.

http://sc.tamu.edu/systems/eos/nehalem.pdf Pour Nehalem, qui est une plate-forme multiprocesseur, les processeurs ont la capacité de "fouiner" (écouter) le bus d'adresses pour les accès des autres processeurs à la mémoire système et à leurs caches internes. Ils utilisent cette capacité d'espionnage pour maintenir la cohérence de leurs caches internes à la fois avec la mémoire système et avec les caches des autres processeurs interconnectés. Si, grâce à cette fonction de surveillance, un processeur détecte qu'un autre processeur a l'intention d'écrire dans un emplacement de mémoire qu'il a actuellement mis en cache dans un état partagé, le processeur surveillant invalidera son bloc de cache, ce qui l'obligera à remplir une ligne de cache la prochaine fois qu'il accédera au même emplacement de mémoire.

oracle hotspot jdk pour l'architecture x86 cpu->

lazySet == unsafe.putOrderedLong == xchg rw( instruction asm qui sert de barrière souple coûtant 20 cycles sur un cpu intel nehelem)

sur x86 (x86_64), une telle barrière est beaucoup moins coûteuse en termes de performances que volatile ou AtomicLong getAndAdd ,

Dans un scénario de file d'attente avec un producteur et un consommateur, la barrière souple de xchg peut forcer la ligne de codes avant le lazySet(séquence+1) pour le thread du producteur à se produire AVANT tout code du thread du consommateur qui consommera (travaillera sur) les nouvelles données, bien sûr le thread du consommateur devra vérifier atomiquement que la séquence du producteur a été incrémentée d'exactement un en utilisant un compareAndSet (séquence, séquence + 1).

J'ai tracé après le code source de Hotspot pour trouver le mapping exact du lazySet au code cpp : http://hg.openjdk.java.net/jdk7/jdk7/hotspot/file/9b0ca45cd756/src/share/vm/prims/unsafe.cpp Unsafe_setOrderedLong -> Définition de SET_FIELD_VOLATILE -> OrderAccess:release_store_fence. Pour x86_64, OrderAccess:release_store_fence est défini comme utilisant l'instruction xchg.

Vous pouvez voir comment il est exactement défini dans le JDK7 (Doug Lea travaille sur de nouveaux éléments pour le JDK 8) : http://hg.openjdk.java.net/jdk7/jdk7/hotspot/file/4fc084dac61e/src/os_cpu/linux_x86/vm/orderAccess_linux_x86.inline.hpp

vous pouvez également utiliser le hdis pour désassembler l'assemblage du code lazySet en action.

Il y a une autre question connexe : A-t-on besoin de mfence quand on utilise xchg ?

6 votes

J'ai du mal à comprendre où vous voulez en venir. Pouvez-vous s'il vous plaît clarifier votre point de vue ?

3 votes

"lazySet == unsafe.putOrderedLong == xchg rw( instruction asm qui sert de barrière souple coûtant 20 cycles sur un cpu intel nehelem) sur x86 (x86_64) une telle barrière est beaucoup moins coûteuse en performance que volatile ou AtomicLong getAndAdd" -> A ma connaissance, ce n'est pas vrai. lazySet/putOrdered est un MOV vers une adresse, c'est pourquoi le livre de cuisine JMM le décrit comme un no-op sur x86.

12voto

Nitsan Wakart Points 613

Une discussion plus large sur les origines et l'utilité de lazySet et du sous-jacent putOrdered peut être trouvée ici : http://psy-lob-saw.blogspot.co.uk/2012/12/atomiclazyset-is-performance-win-for.html

Pour résumer : lazySet est une écriture volatile faible dans le sens où elle agit comme un store-store et non comme un store-load fence. Cela revient à dire que lazySet est compilé en JIT avec une instruction MOV qui ne peut pas être réordonnée par le compilateur plutôt qu'avec l'instruction beaucoup plus coûteuse utilisée pour un ensemble volatile.

Lorsque vous lisez la valeur, vous finissez toujours par faire une lecture volatile (avec un Atomic*.get() dans tous les cas).

LazySet offre à un auteur unique un mécanisme d'écriture volatile cohérent, c'est-à-dire qu'il est parfaitement légitime pour un auteur unique d'utiliser lazySet pour incrémenter un compteur, plusieurs threads incrémentant le même compteur devront résoudre les écritures concurrentes en utilisant le CAS, ce qui est exactement ce qui se passe sous la couverture d'Atomic* pour incAndGet.

0 votes

Exactement, pourquoi ne pouvons-nous pas dire que c'est une simple StoreStore barrière, mais no a StoreLoad ?

5voto

jyluo Points 29

Voici ce que j'ai compris, corrigez-moi si je me trompe : Vous pouvez penser à lazySet() comme "semi" volatile : c'est fondamentalement une variable non volatile en termes de lecture par d'autres threads, c'est-à-dire que la valeur définie par lazySet peut ne pas être visible par d'autres threads. Mais elle devient volatile lorsqu'une autre opération d'écriture se produit (pouvant provenir d'autres threads). Le seul impact de lazySet que je puisse imaginer est le suivant compareAndSet . Ainsi, si vous utilisez lazySet() , get() d'autres threads peuvent toujours obtenir l'ancienne valeur, mais compareAndSet() aura toujours la nouvelle valeur puisqu'il s'agit d'une opération d'écriture.

1 votes

Tu ne veux pas dire compareAndSet ?

4voto

Mathieu Lalonde Points 31

Martin Thompson fait un bon usage de lazySet dans son exemple de file d'attente à consommateur/producteur unique dans cette présentation (qcon San Francisco 2012) : http://ebookbrowsee.net/martinthompson-lockfreealgorithmsforultimateperformancemovedtoballrooma-pdf-d522161427

Voir le code ici : https://github.com/mjpt777/examples

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X