Поиск по сайту:

AtomicInteger в Java


Сегодня мы рассмотрим AtomicInteger в Java. Атомарные операции выполняются в одном блоке задачи без вмешательства других операций. Атомарные операции необходимы в многопоточной среде, чтобы избежать несогласованности данных.

AtomicInteger

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) {
        // processing some job
        try {
            Thread.sleep(i * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

Если вы запустите вышеуказанную программу, вы заметите, что значение count варьируется между 5,6,7,8. Причина в том, что count++ не является атомарной операцией. Таким образом, к тому времени, когда один поток прочитает это значение и увеличит его на единицу, другой поток прочитает более старое значение, что приведет к неправильному результату. Чтобы решить эту проблему, нам нужно убедиться, что операция приращения счетчика является атомарной, мы можем сделать это с помощью синхронизации, но Java 5 java.util.concurrent.atomic предоставляет классы-оболочки для int и long, которые можно использовать для выполнения этой атомарной операции без использования синхронизации.

Пример Java AtomicInteger

Вот обновленная программа, которая всегда будет выводить значение счетчика как 8, потому что метод AtomicInteger incrementAndGet() атомарно увеличивает текущее значение на единицу.

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) {
        // processing some job
        try {
            Thread.sleep(i * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

Преимущества использования классов Concurrency для атомарных операций заключаются в том, что нам не нужно беспокоиться о синхронизации. Это улучшает читаемость кода и снижает вероятность ошибок. Также предполагается, что классы параллелизма атомарных операций более эффективны, чем синхронизация, которая включает блокировку ресурсов.