web-dev-qa-db-fra.com

Quand est-il préférable d'utiliser un booléen volatil dans Java plutôt qu'AtomicBoolean?

J'ai regardé les autres questions volatiles vs Atomicxxxx dans SO (y compris celui-ci ) et j'ai lu la description de Java.util.current .atomic , et je ne suis pas tout à fait satisfait des nuances.

Si j'essaie de décider entre l'utilisation de volatile boolean Et AtomicBoolean, y a-t-il des différences pratiques en plus des opérations atomiques de lecture-modification-écriture offertes par AtomicBoolean? (par exemple compareAndSet() et getAndSet())

Supposons que j'ai

volatile boolean flag;

Ensuite, un ou plusieurs threads définissent l'indicateur (mais ne le désactivent pas). Si j'ai un thread qui lit l'indicateur, et s'il est défini, une action, puis efface l'indicateur, volatile est-elle adéquate?

Y a-t-il un coût plus élevé pour AtomicBoolean que pour un booléen volatil, en termes de

  • espace mémoire
  • performance hit (volatile boolean semble nécessiter une clôture de mémoire, AtomicBoolean semble nécessiter une clôture de mémoire + quelques verrouillages mineurs sur les opérations CAS selon la description Java.util.current.atomic)

Mon appel est d'aller simplement avec AtomicBoolean et d'être en sécurité, mais je veux comprendre s'il y a jamais une situation pour utiliser volatile boolean À la place (par exemple, si j'en avais des milliers d'instances et que les performances étaient un problème).

54
Jason S

Essentiellement, tout AtomicBoolean est un volatile boolean dans un objet.

Il y aura une petite surcharge par objet. Probablement insignifiant, mais peut-être plus de mémoire pour entrer dans le cache.

Si vous avez besoin d'utiliser AtomicBooleanFieldUpdater, il y a beaucoup de surcharge de performances. Cela peut être correct si vous ne le faites pas souvent (comme attach dans NIO).

17

La principale différence entre AtomicBoolean et volatile d'un point de vue pratique est que l'opération de comparaison et de définition n'est pas atomique avec les variables volatile.

 volatile boolean b;

 void foo() {
   if( b ) {
     //Here another thread might have already changed the value of b to false
     b = false;
   }
 }

Mais étant donné que toutes vos écritures simultanées sont idempotentes et que vous ne lisez que sur un seul fil, cela ne devrait pas être un problème.

71
biziclop

Je ne suis pas sûr d'être entièrement d'accord avec les autres réponses ici; La réponse de biziclop est juste dans la mesure où elle va, mais je ne suis pas sûr que nous pouvons conclure que vous êtes en sécurité à moins que nous connaissions plus en détail.

Dans le cas simple, l'entrelacement pourrait ressembler à ceci:

Thread 1 (writer)   Thread 2 (Writer)  Thread 3 (Reader)
-----------------   -----------------  -----------------
flag = true;
                                       if (flag) {
                    flag = true;
                                         flag = false;
                                         doStuff();

et cela pourrait être bien (le deuxième ensemble de flag à true n'a pas d'importance, car doStuff() verra probablement ce que Thread 2 doit faire.

Cependant, si vous inversez le fil de commande 3:

Thread 1 (writer)   Thread 2 (Writer)  Thread 3 (Reader)
-----------------   -----------------  -----------------
flag = true;
                                       if (flag) {
                                         doStuff();
                    flag = true;
                                         flag = false;

alors la mise à jour de Thread 2 pourrait être perdue.

Bien sûr, vous devez être également prudent avec tout ce que fait Thread 2, pour vous assurer qu'il est visible par Thread 3. S'il y a un autre état que Thread 2 doit définir, l'ordre devient également important.

Dans le cas simple, oui, ça va, mais si cela devient plus complexe que le simple effleurement de drapeaux, cela devient beaucoup plus difficile à raisonner.

19
Cowan

Il y a beaucoup de bonnes informations ici. Cependant, j'ajouterais une autre différence qui pourrait être utile. Vous pouvez avoir un tableau d'AtomicBooleans mais vous ne pouvez pas (à ma connaissance) avoir un tableau de booléens volatils.

7
snapfractalpop

Ensuite, un ou plusieurs threads définissent l'indicateur (mais ne le désactivent pas). Si j'ai un thread qui lit l'indicateur, et s'il est défini, une action, puis efface l'indicateur, est volatile adéquate?

Oui, si vous n'avez pas besoin des capacités spéciales d'AtomicBoolean, il est tout à fait correct d'utiliser volatile pour cela. En fait, c'est l'une des rares utilisations raisonnables de volatile.

2
Sergei Tachenov