231 votes

Volatile boolean vs AtomicBoolean

Que fait AtomicBoolean que boolean volatile ne peut pas réaliser?

253voto

teto Points 1439

J'utilise des champs volatils lorsque ledit champ est UNIQUEMENT MIS À JOUR par son thread propriétaire et que la valeur est seulement lue par d'autres threads, vous pouvez le considérer comme un scénario de publication/abonnement où il y a de nombreux observateurs mais un seul éditeur. Cependant, si ces observateurs doivent effectuer une certaine logique basée sur la valeur du champ et ensuite renvoyer une nouvelle valeur, alors j'utilise des variables Atomic* ou des verrous ou des blocs synchronisés, selon ce qui me convient le mieux. Dans de nombreux scénarios concurrents, cela revient à obtenir la valeur, la comparer à une autre et la mettre à jour si nécessaire, d'où les méthodes compareAndSet et getAndSet présentes dans les classes Atomic*.

Consultez la JavaDocs du package java.util.concurrent.atomic pour une liste des classes Atomic et une excellente explication de leur fonctionnement (je viens de découvrir qu'elles sont sans verrou, donc elles ont un avantage sur les verrous ou les blocs synchronisés)

91voto

Cephalopod Points 4927

Ils sont tout à fait différents. Considérez cet exemple pour un entier volatile :

volatile int i = 0;
void incIBy5() {
    i += 5;
}

Si deux threads appellent la fonction simultanément, i pourrait être égal à 5 par la suite, puisque le code compilé sera quelque peu similaire à ceci (à l'exception que vous ne pouvez pas synchroniser sur un int) :

void incIBy5() {
    int temp;
    synchronisé(i) { temp = i }
    synchronisé(i) { i = temp + 5 }
}

Si une variable est volatile, chaque accès atomique à celle-ci est synchronisé, mais il n'est pas toujours évident de déterminer ce qui qualifie réellement un accès atomique. Avec un objet Atomic*, il est garanti que chaque méthode est "atomique".

Ainsi, si vous utilisez un AtomicInteger et getAndAdd(int delta), vous pouvez être sûr que le résultat sera 10. De la même manière, si deux threads négativent simultanément une variable boolean, avec un AtomicBoolean, vous pouvez être sûr qu'elle aura la valeur d'origine par la suite, avec un volatile boolean, non.

Ainsi chaque fois que vous avez plus d'un thread modifiant un champ, vous devez le rendre atomique ou utiliser une synchronisation explicite.

Le but du volatile est différent. Considérez cet exemple :

volatile boolean stop = false;
void loop() {
    while (!stop) { ... }
}
void stop() { stop = true; }

Si vous avez un thread exécutant loop() et un autre thread appelant stop(), vous pourriez rencontrer une boucle infinie si vous omettez volatile, puisque le premier thread pourrait mettre en cache la valeur de stop. Ici, le volatile sert d'indice au compilateur pour être un peu plus prudent avec les optimisations.

54voto

nanda Points 12764

Vous ne pouvez pas faire compareAndSet, getAndSet en tant qu'opération atomique avec un boolean volatile (à moins bien sûr de le synchroniser).

42voto

Nam San Points 490

AtomicBoolean possède des méthodes qui exécutent leurs opérations combinées de manière atomique et sans avoir besoin d'utiliser un bloc synchronized. D'autre part, volatile boolean ne peut exécuter des opérations combinées que s'il est fait à l'intérieur d'un bloc synchronized.

Les effets de mémoire de la lecture/écriture de volatile boolean sont identiques aux méthodes get et set de AtomicBoolean respectivement.

Par exemple, la méthode compareAndSet exécutera atomiquement ce qui suit (sans bloc synchronized) :

if (value == expectedValue) {
    value = newValue;
    return true;
} else {
    return false;
}

Par conséquent, la méthode compareAndSet vous permettra d'écrire du code qui est garanti de s'exécuter une seule fois, même lorsqu'il est appelé par plusieurs threads. Par exemple :

final AtomicBoolean isJobDone = new AtomicBoolean(false);

...

if (isJobDone.compareAndSet(false, true)) {
    listener.notifyJobDone();
}

Est garanti de ne notifier le auditeur qu'une seule fois (en supposant qu'aucun autre thread ne réinitialise l'AtomicBoolean à false après l'avoir défini sur true).

14voto

dhblah Points 2337

Le mot-clé volatile garantit une relation de happens-before parmi les threads partageant cette variable. Cela ne vous garantit pas que 2 threads ou plus n'interrompront pas mutuellement lors de l'accès à cette variable booléenne.

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