web-dev-qa-db-fra.com

Java référence volatile vs AtomicReference

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?

129
auramo

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 variable volatile.
  • set a pour effet mémoire d'écrire (affecter) une variable volatile.

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.

107
pgras

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 ().

40
Avi

Il existe plusieurs différences et compromis:

  1. 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.

  2. l'empreinte mémoire est multipliée (en supposant un environnement OOP compressé, ce qui est vrai pour la plupart des machines virtuelles):

    • ref volatile = 4b
    • AtomicReference = 4b + 16b (en-tête d'objet 12b + champ de référence 4b)
  3. 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:

  • Vous avez seulement besoin de get/set? Restez avec un champ volatil, la solution la plus simple et les frais généraux les plus bas.
  • Besoin de fonctionnalités supplémentaires? S'il s'agit d'une partie sensible à la performance (vitesse/surcharge de mémoire) de votre code, faites un choix entre 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.
8
Nitsan Wakart

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.

6
endless

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.

2
Peter Lawrey