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