Quelle est la différence entre les méthodes lazySet
et set
de AtomicInteger
? La documentation n'a pas grand-chose à dire sur lazySet
:
Définit finalement la valeur donnée.
Il semble que la valeur stockée ne sera pas immédiatement définie sur la valeur souhaitée, mais qu'elle sera plutôt programmée pour être définie dans le futur. Mais, quelle est l'utilisation pratique de cette méthode? Un exemple?
la source
Atomic*
portée).lazySet peut être utilisé pour la communication inter thread rmw, car xchg est atomique, comme pour la visibilité, lorsque le processus de thread d'écriture modifie un emplacement de ligne de cache, le processeur du thread de lecture le verra à la lecture suivante, car le protocole de cohérence du cache du processeur Intel garantira 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» (espionner) le bus d'adresses pour les accès d'autres processeurs à la mémoire système et dans leurs caches internes. Ils utilisent cette capacité de surveillance pour garder leurs caches internes cohérents à la fois avec la mémoire système et avec les caches dans d'autres processeurs interconnectés. Si, grâce à la 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 l'état partagé, le processeur de surveillance invalidera son bloc de cache, le forçant à effectuer un remplissage de ligne de cache la prochaine fois qu'il accédera au même emplacement de mémoire .
oracle hotspot jdk pour architecture cpu x86->
lazySet == unsafe.putOrderedLong == xchg rw (instruction asm qui sert de barrière souple coûtant 20 cycles sur le processeur nehelem Intel)
sur x86 (x86_64) une telle barrière est beaucoup moins chère en termes de performances que volatile ou AtomicLong getAndAdd,
Dans un scénario de file d'attente à un producteur et un consommateur, la barrière souple xchg peut forcer la ligne de codes avant le lazySet (séquence + 1) pour que le thread producteur se produise AVANT tout code de thread consommateur qui consommera (travaillera sur) les nouvelles données, bien sûr Le thread consommateur devra vérifier de manière atomique que la séquence du producteur a été incrémentée d'exactement un en utilisant un compareAndSet (sequence, sequence + 1).
J'ai suivi le code source de Hotspot pour trouver le mappage 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 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 jdk7 (doug lea travaille sur de nouveaux éléments pour 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 hdis pour désassembler l'assembly du code lazySet en action.
Il y a une autre question connexe: avons-nous besoin de mfence lors de l'utilisation de xchg
la source
Une discussion plus large sur les origines et l'utilité de lazySet et du putOrdered sous-jacent 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ù il agit comme un magasin de stockage et non comme une clôture de stockage. Cela se résume à lazySet étant compilé JIT en une instruction MOV qui ne peut pas être réordonnée par le compilateur plutôt que l'instruction nettement plus coûteuse utilisée pour un ensemble volatile.
Lors de la lecture de la valeur, vous finissez toujours par faire une lecture volatile (avec un Atomic * .get () dans tous les cas).
lazySet offre à un seul écrivain un mécanisme d'écriture volatile cohérent, c'est-à-dire qu'il est parfaitement légitime pour un seul écrivain d'utiliser lazySet pour incrémenter un compteur, plusieurs threads incrémentant le même compteur devront résoudre les écritures concurrentes en utilisant CAS, ce qui se passe exactement sous les jaquettes d'Atomic * pour incAndGet.
la source
StoreStore
barrière, mais pas uneStoreLoad
?À partir du résumé du package Concurrent-atomic
lazySet a les effets de mémoire d'écrire (assigner) une variable volatile sauf qu'il permet des réorganisations avec des actions mémoire ultérieures (mais pas précédentes) qui n'imposent pas elles-mêmes des contraintes de réorganisation avec les écritures non volatiles ordinaires. Entre autres contextes d'utilisation, lazySet peut s'appliquer lors de l'annulation, dans un souci de garbage collection, une référence qui n'est plus jamais accédée.
Si vous êtes curieux de lazySet, vous vous devez également d'autres explications.
la source
Voici ma compréhension, corrigez-moi si je me trompe: vous pouvez penser à
lazySet()
"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 pour les autres fils. Mais il devient volatil lorsqu'une autre opération d'écriture se produit (peut être à partir d'autres threads). Le seul impact de lazySet que je peux imaginer estcompareAndSet
. Donc, si vous utilisezlazySet()
,get()
d'autres threads peuvent toujours obtenir l'ancienne valeur, maiscompareAndSet()
auront toujours la nouvelle valeur car il s'agit d'une opération d'écriture.la source
compareAndSet
?Re: essayez de le baisser -
Vous pouvez considérer cela comme un moyen de traiter un champ volatil comme s'il n'était pas volatil pour une opération de magasin particulière (par exemple: ref = null;).
Ce n'est pas tout à fait exact, mais cela devrait suffire pour que vous puissiez prendre une décision entre «OK, je m'en fiche» et «Hmm, laissez-moi réfléchir un peu».
la source