Y a-t-il une différence entre une référence d'objet volatile
et AtomicReference
au cas où j'utiliserais simplement les méthodes get()
et set()
- de AtomicReference
?
La réponse courte est: Non.
Depuis le Java.util.concurrent.atomic package doc :
Les effets de mémoire pour les accès et les mises à jour de l'atome suivent généralement les règles pour les volatiles:
get
a pour effet mémoire de lire une variablevolatile
.set
a pour effet mémoire d'écrire (affecter) une variablevolatile
.
Soit dit en passant, la doc du package est très bonne et tout est expliqué ...
lazySet
(introduit dans Java 6) est une opération plus récente qui a une sémantique inaccessible via les variables volatile
; voir cet article pour Plus d'information.
Non, il n'y en a pas.
La puissance supplémentaire fournie par AtomicReference est la méthode compareAndSet () et ses amis. Si vous n'avez pas besoin de ces méthodes, une référence volatile fournit la même sémantique que AtomicReference.set () et .get ().
Il existe plusieurs différences et compromis:
L'utilisation d'un AtomicReference
get/set a la même sémantique JMM qu'un champ volatile (comme l'indique javadoc), mais le AtomicReference
est un wrapper autour d'une référence, donc tout accès au champ implique une poursuite supplémentaire du pointeur.
l'empreinte mémoire est multipliée (en supposant un environnement OOP compressé, ce qui est vrai pour la plupart des machines virtuelles):
AtomicReference
= 4b + 16b (en-tête d'objet 12b + champ de référence 4b)AtomicReference
offre une API plus riche qu'une référence volatile. Vous pouvez récupérer l'API pour la référence volatile en utilisant un AtomicFieldUpdater
, ou avec Java 9 a VarHandle
. Vous pouvez également accéder directement à Sun.misc.Unsafe
si vous aimez courir avec des ciseaux. AtomicReference
lui-même est implémenté à l'aide de Unsafe
.
Alors, quand est-il bon de choisir l'un plutôt que l'autre:
AtomicReference
/AtomicFieldUpdater
/Unsafe
où vous avez tendance à payer pour la lisibilité et le risque de votre gain de performance. Si ce n'est pas une zone sensible, optez simplement pour AtomicReference
. Les rédacteurs de bibliothèques utilisent généralement une combinaison de ces méthodes en fonction des JDK ciblés, des restrictions d'API attendues, des contraintes de mémoire, etc.code source JDK est l'un des meilleurs moyens de répondre à des confusions comme celle-ci. Si vous regardez le code dans AtomicReference, il utilise une variable volatie pour le stockage d'objets.
private volatile V value;
Donc, évidemment, si vous allez simplement utiliser get () et set () sur AtomicReference, c'est comme utiliser une variable volatile. Mais comme d'autres lecteurs l'ont fait remarquer, AtomicReference fournit une sémantique CAS supplémentaire. Donc, décidez d'abord si vous voulez la sémantique CAS ou non, et si vous le faites, utilisez AtomicReference.
AtomicReference fournit des fonctionnalités supplémentaires qu'une variable volatile ordinaire ne fournit pas. Comme vous avez lu l'API, vous le saurez, mais il fournit également un verrou qui peut être utile pour certaines opérations.
Cependant, à moins que vous n'ayez besoin de cette fonctionnalité supplémentaire, je vous suggère d'utiliser un champ volatile simple.