Le variabili atomiche in java

di  Antonio Coschignano, giovedě 13 settembre 2012

Nel package java.util.concurrent.atomic sono definite una serie di classi che supportano le operazioni atomiche su singole variabili. Che significa operazioni atomiche? Be, se siamo in ambienti multitrheading, dove diversi thread operano su una singola variabile, un thread per volta può accedere e leggere o modificare la variabile. Se così non fosse si creerebbero stati di inconsistenza dei dati.

Ci sono diversi modi per garantire l'atomicità delle operazioni su singole variabili. Ad esempio, mettiamo il caso di avere un contatore, per garantire l'atomicità possiamo utilizzare la keyword synchronized su ogni metodo. Vediamo:

class Contatore {

    private int counter = 0;

    public synchronized void incrementa() {
        counter++;
    }

    public synchronized void decrementa() {
        counter--;
    }

    public synchronized int valore() {
        return counter;
    }
}

Questa si, è una buona soluzione, ma per oggetti un po più complessi si finisce per implementare delle 'zone' synchronized inutili e quindi ne va delle prestazioni della classe stessa. La sostituzione del campo int con un AtomicInteger ci permette di evitare stati di inconsistenza senza ricorrere alla sincronizzazione. La classe definisce la variabile interna come campo volatile quindi con aggiornamento atomico della variabile. Esempio del contatore con AtomicInteger:

class AtomicCounter {

    private AtomicInteger counter = new AtomicInteger(0);

    public void increment() {
        counter.incrementAndGet();
    }

    public void decrement() {
       counter.decrementAndGet();
    }

    public int value() {
        return counter.get();
    }
}

Esiste ancora un altro metodo importante come set():

    public void increment(int s) {
        counter.set(s);
    }
Nel package abbiamo altre classi come per i boolean abbiamo AtomicBoolean, poi per il long AtomicLong etc.. ma che sono implementate sempre con lo stesso meccanismo.