AtomicInteger en Java

Aujourd’hui, nous allons examiner AtomicInteger en Java. Les opérations atomiques sont effectuées dans une unité de tâche unique sans interférence d’autres opérations. Les opérations atomiques sont nécessaires dans un environnement multi-thread pour éviter toute incohérence des données.

AtomicInteger

Créons un programme multi-thread simple où chaque thread incrémente la variable partagée count 4 fois. Ainsi, s’il y a deux threads, après leur exécution, la valeur de count devrait être 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) {
        // traitement d'une tâche
        try {
            Thread.sleep(i * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

Si vous exécutez le programme ci-dessus, vous remarquerez que la valeur de count varie entre 5, 6, 7, 8. La raison en est que count++ n’est pas une opération atomique. Ainsi, au moment où un thread lit sa valeur et l’incrémente de un, l’autre thread a lu l’ancienne valeur, entraînant un résultat incorrect. Pour résoudre ce problème, nous devons nous assurer que l’opération d’incrémentation sur count est atomique, nous pouvons le faire en utilisant la synchronisation, mais Java 5 fournit des classes d’enrobage pour int et long dans java.util.concurrent.atomic qui peuvent être utilisées pour réaliser cette opération atomique sans utiliser la synchronisation.

Exemple Java AtomicInteger

Voici le programme mis à jour qui affichera toujours la valeur de la variable « count » comme étant 8, car la méthode incrementAndGet() de AtomicInteger incrémente atomiquement la valeur actuelle de un.

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) {
        // traitement d'une tâche
        try {
            Thread.sleep(i * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

Les avantages de l’utilisation des classes de concurrence pour les opérations atomiques sont que nous n’avons pas à nous soucier de la synchronisation. Cela améliore la lisibilité du code et réduit les chances d’erreurs. De plus, les opérations atomiques avec les classes de concurrence sont supposées être plus efficaces que la synchronisation, qui implique le verrouillage des ressources.

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