Quando devo usare AtomicBoolean in Java?


Risposte:


244

Quando più thread devono controllare e modificare il valore booleano. Per esempio:

if (!initialized) {
   initialize();
   initialized = true;
}

Questo non è thread-safe. Puoi risolverlo usando AtomicBoolean:

if (atomicInitialized.compareAndSet(false, true)) {
    initialize();
}

51
Non sembra un esempio reale - altri thread possono vedere truequando initialize()non sono stati completati. Quindi, funziona solo se altri thread non si preoccupano del completamento di initialize().
axtavt,

6
@axtavt: Penso che sia un esempio del mondo reale perfettamente valido se initializedviene semplicemente utilizzato per garantire che uno e un solo thread invochino il initialize()metodo. Ovviamente initializedessere vero non significa che l'inizializzazione sia stata definitivamente completata in questo caso, quindi forse un termine leggermente diverso sarebbe meglio qui. Ancora una volta, dipende da cosa viene utilizzato.
ColinD,

14
occorrerebbero 2 booleani per initStarted e initCompleted, quindi il primo thread imposta initStarted e chiama initialise (), il resto attende fino a quando initCompleted è true.
Martin,

3
@Bozho - legge e scrive nei campi booleani sono atomici, giusto ?, Ora, volatile mi dà l'ultimo valore del campo booleano. Quindi, in effetti, non sarebbe lo volatile booleanstesso AtomicBoolean?
TheLostMind

2
@Martin: non c'è modo diretto di aspettare che un booleano diventi realtà; hai bisogno di meccanismi aggiuntivi. L'approccio più sensato è usare un synchronizedblocco, nel qual caso non è più necessario un AtomicBoolean, solo un volatile boolean. ( if(! this.initialized) { synchronized(this) { if(! this.initialized) { initialize(); this.initialized = true; } } }assicurerà che solo un thread chiami initializee che tutti gli altri thread aspettino che ciò avvenga, a condizione che initializedsia contrassegnato volatile.)
ruakh

52

Ecco le note (dal libro di Brian Goetz ) che ho fatto, che potrebbero esserti di aiuto

Classi AtomicXXX

  • fornire un'implementazione comparativa e di scambio non bloccante

  • Sfrutta il supporto fornito dall'hardware (le istruzioni CMPXCHG su Intel) Quando molti thread eseguono il codice che utilizza queste API di concorrenza atomica, si ridimensioneranno molto meglio del codice che utilizza i monitor / sincronizzazione a livello di oggetto. Poiché i meccanismi di sincronizzazione di Java fanno attendere il codice, quando ci sono molti thread in esecuzione attraverso le sezioni critiche, una notevole quantità di tempo della CPU viene impiegata nella gestione del meccanismo di sincronizzazione stesso (in attesa, notifica, ecc.). Poiché la nuova API utilizza costrutti a livello di hardware (variabili atomiche) e attende e blocca algoritmi liberi per implementare la sicurezza dei thread, si dedica molto più tempo alla CPU "facendo cose" piuttosto che a gestire la sincronizzazione.

  • non solo offrono una migliore produttività, ma forniscono anche una maggiore resistenza ai problemi di vivacità come deadlock e inversione di priorità.


34

Ci sono due ragioni principali per cui puoi usare un booleano atomico. Innanzitutto è modificabile, è possibile passarlo come riferimento e modificare il valore associato al booleano stesso, ad esempio.

public final class MyThreadSafeClass{

    private AtomicBoolean myBoolean = new AtomicBoolean(false);
    private SomeThreadSafeObject someObject = new SomeThreadSafeObject();

    public boolean doSomething(){
         someObject.doSomeWork(myBoolean);
         return myBoolean.get(); //will return true
    }
}

e nella classe someObject

public final class SomeThreadSafeObject{
    public void doSomeWork(AtomicBoolean b){
        b.set(true);
    }
}

Ancora più importante, il thread è sicuro e può indicare agli sviluppatori che mantengono la classe che questa variabile dovrebbe essere modificata e letta da più thread. Se non si utilizza un AtomicBoolean, è necessario sincronizzare la variabile booleana in uso dichiarandola volatile o sincronizzandosi con la lettura e la scrittura del campo.


4
Per amore di Dio, questo doveva solo mostrare la mutabilità dell'oggetto stesso. L'ho scritto specificamente a scopo dimostrativo.
John Vint,

E ancora di più, se fosse TUTTO ciò che stava accadendo, allora sì, tornerà sempre vero
John Vint,

Ciò non sta provando se è o non è thread-safe. Posso terminare i miei frammenti di codice per rendere la classe molto sicura per i thread, ma questo uccide solo il mio punto.
John Vint,

1
Penso che solo Volatile non sia abbastanza. Pensa a una situazione in cui due thread che leggono e scrivono lo stesso valore direttamente dalla memoria principale, non c'è alcuna sincronizzazione tra quei thread - potrebbero sorgere problemi di concorrenza.
Shay Tsadok,

1
Hai ragione, non sarebbe sufficiente per il set atomico quindi controllare le operazioni, anche se dall'OP non c'era abbastanza contesto per fare questo presupposto. Dire che volatile potrebbe non essere abbastanza è sempre vero a seconda della situazione ovviamente.
John Vint,


5

Estratto dalla descrizione del pacchetto

Descrizione del pacchetto java.util.concurrent.atomic: un piccolo toolkit di classi che supporta la programmazione thread-free senza blocco su singole variabili. [...]

Le specifiche di questi metodi consentono alle implementazioni di utilizzare efficienti istruzioni atomiche a livello di macchina che sono disponibili su processori contemporanei. [...]

Le istanze delle classi AtomicBoolean, AtomicInteger, AtomicLong e AtomicReference forniscono l'accesso e gli aggiornamenti a una singola variabile del tipo corrispondente. [...]

Gli effetti di memoria per gli accessi e gli aggiornamenti di atomica generalmente seguono le regole per i volatili:

  • get ha gli effetti di memoria della lettura di una variabile volatile.
  • set ha gli effetti di memoria della scrittura (assegnazione) di una variabile volatile.
  • weakCompareAndSet legge atomicamente e scrive in modo condizionale una variabile, è ordinata rispetto ad altre operazioni di memoria su quella variabile, ma agisce altrimenti come una normale operazione di memoria non volatile.
  • compareAndSet e tutte le altre operazioni di lettura e aggiornamento come getAndIncrement hanno gli effetti di memoria sia della lettura che della scrittura di variabili volatili.
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.