AtomicInteger in Java

Oggi daremo un’occhiata a AtomicInteger in Java. Le operazioni atomiche vengono eseguite in un’unica unità di compito senza interferenze da altre operazioni. Le operazioni atomiche sono necessarie in un ambiente multithreading per evitare l’incoerenza dei dati.

AtomicInteger

Creiamo un semplice programma multithreading in cui ogni thread incrementa la variabile count condivisa 4 volte. Quindi, se ci sono due thread, dopo che hanno terminato, il valore di count dovrebbe essere 8. JavaAtomic.java

package com.journaldev.concurrency;

public class JavaAtomic {

    public static void main(String[] args) throws InterruptedException {

        ProcessingThread pt = new ProcessingThread();
        Thread t1 = new Thread(pt, "t1");
        t1.start();
        Thread t2 = new Thread(pt, "t2");
        t2.start();
        t1.join();
        t2.join();
        System.out.println("Processing count=" + pt.getCount());
    }

}

class ProcessingThread implements Runnable {
    private int count;

    @Override
    public void run() {
        for (int i = 1; i < 5; i++) {
            processSomething(i);
            count++;
        }
    }

    public int getCount() {
        return this.count;
    }

    private void processSomething(int i) {
        // elaborazione di un lavoro
        try {
            Thread.sleep(i * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

Se esegui il programma sopra, noterai che il valore di count varia tra 5, 6, 7, 8. Il motivo è perché count++ non è un’operazione atomica. Quindi, nel momento in cui un thread legge il suo valore e lo incrementa di uno, l’altro thread ha letto il valore precedente, portando a un risultato errato. Per risolvere questo problema, dovremo assicurarci che l’operazione di incremento su count sia atomica, possiamo farlo usando Synchronization ma Java 5 java.util.concurrent.atomic fornisce classi wrapper per int e long che possono essere utilizzate per ottenere questa operazione atomica senza utilizzo di Synchronization.

Esempio di AtomicInteger Java

Ecco il programma aggiornato che restituirà sempre il valore del contatore come 8 perché il metodo incrementAndGet() di AtomicInteger incrementa atomicamente il valore corrente di uno.

package com.journaldev.concurrency;

import java.util.concurrent.atomic.AtomicInteger;

public class JavaAtomic {

    public static void main(String[] args) throws InterruptedException {

        ProcessingThread pt = new ProcessingThread();
        Thread t1 = new Thread(pt, "t1");
        t1.start();
        Thread t2 = new Thread(pt, "t2");
        t2.start();
        t1.join();
        t2.join();
        System.out.println("Processing count=" + pt.getCount());
    }
}

class ProcessingThread implements Runnable {
    private AtomicInteger count = new AtomicInteger();

    @Override
    public void run() {
        for (int i = 1; i < 5; i++) {
            processSomething(i);
            count.incrementAndGet();
        }
    }

    public int getCount() {
        return this.count.get();
    }

    private void processSomething(int i) {
        // elaborazione di un lavoro
        try {
            Thread.sleep(i * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

I vantaggi dell’utilizzo delle classi di concorrenza per le operazioni atomiche sono che non è necessario preoccuparsi della sincronizzazione. Ciò migliora la leggibilità del codice e riduce la probabilità di errori. Inoltre, le operazioni atomiche delle classi di concorrenza sono considerate più efficienti della sincronizzazione, che coinvolge il blocco delle risorse.

Source:
https://www.digitalocean.com/community/tutorials/atomicinteger-java