AtomicInteger.incrementAndGet(): примеры (JAVA)
AtomicInteger.incrementAndGet(): intОписание метода incrementAndGet()
Метод incrementAndGet() класса java.util.concurrent.atomic.AtomicInteger выполняет атомарное приращение значения на единицу и возвращает новое значение. Подпись метода:
public final int incrementAndGet()
Ключевые свойства:
- Аргументы: метод не принимает аргументов.
- Возвращаемое значение: целое (
int) - новое значение после приращения. - Атомарность: операция выполняется атомарно - гарантируется, что при конкурентном доступе каждая операция выполнится без вмешательства других потоков.
- Память и видимость: методы
AtomicIntegerобеспечивают семантику памяти, эквивалентную использованию volatile-поля и CAS, поэтому изменения видимы другим потокам. - Переполнение: при достижении границы
Integer.MAX_VALUEдальнейшее приращение приводит к переполнению по правилу двухс complement (то есть переход к отрицательным значениям), исключений не выбрасывается. - Исключения: сам метод не выбрасывает проверяемых исключений; возможен
NullPointerExceptionпри обращении к null-ссылке на объект.
Типичные области применения: счётчики посещений, номера задач, простые счётчики событий, агрегирование метрик в многопоточных приложениях, где требуется неблокирующая операция инкремента.
Ограничения и замечания
- Метод обеспечивает атомарность только для одной операции; если требуется атомарная комбинация нескольких действий, потребуется дополнительная синхронизация или другие атомарные примитивы.
- В сценариях с очень высокой конкуренцией для счётчиков предпочтительнее рассмотреть
LongAdderилиLongAccumulatorиз-за лучшей масштабируемости.
Короткие примеры использования
Пример 1: простой однопоточный вызов.
import java.util.concurrent.atomic.AtomicInteger;
public class Main {
public static void main(String[] args) {
AtomicInteger ai = new AtomicInteger(0);
int newVal = ai.incrementAndGet();
System.out.println("Новое значение: " + newVal);
}
}
Новое значение: 1
Пример 2: сравнение с getAndIncrement() (возвращает старое значение).
AtomicInteger ai = new AtomicInteger(5);
int after = ai.incrementAndGet();
int before = ai.getAndIncrement();
System.out.println("after=" + after + ", before=" + before + ", final=" + ai.get());
after=6, before=6, final=7
Пример 3: многопоточный инкремент с ExecutorService.
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
public class CounterExample {
public static void main(String[] args) throws InterruptedException {
AtomicInteger counter = new AtomicInteger(0);
ExecutorService ex = Executors.newFixedThreadPool(4);
for (int i = 0; i < 4; i++) {
ex.submit(() -> {
for (int j = 0; j < 1000; j++) {
counter.incrementAndGet();
}
});
}
ex.shutdown();
ex.awaitTermination(5, TimeUnit.SECONDS);
System.out.println("Итоговый счётчик: " + counter.get());
}
}
Итоговый счётчик: 4000
Похожие Java-методы и классы
- getAndIncrement()
- addAndGet(int delta)
- getAndAdd(int delta)
- updateAndGet/ getAndUpdate
- AtomicLong / LongAdder / LongAccumulator
- compareAndSet
Возвращает предыдущее значение и затем увеличивает на 1. Отличие от incrementAndGet(): порядок возврата значения.
Атомарно добавляет значение delta и возвращает результат.
Атомарно добавляет delta, но возвращает старое значение.
Принимают функцию обновления (IntUnaryOperator) для атомарного вычисления нового значения.
AtomicLong - для 64-битного счётчика. LongAdder и LongAccumulator - оптимизированы для высокой конкуренции, но LongAdder не всегда возвращает точное промежуточное значение при параллельных обновлениях, хотя итоговый суммарный результат корректен.
Используется для ручной реализации сложной атомарной логики. Предпочтителен, если требуется условное обновление.
Аналоги в других языках и особенности
- C# (Interlocked)
using System;
using System.Threading;
class P { static void Main(){ int x=0; Console.WriteLine(Interlocked.Increment(ref x)); }}
1
Interlocked.Increment возвращает новое значение, аналогично incrementAndGet().
package main
import (
"fmt"
"sync/atomic"
)
func main(){ var x int32 = 0; fmt.Println(atomic.AddInt32(&x, 1)) }
1
atomic.AddInt32 возвращает новое значение.
import java.util.concurrent.atomic.AtomicInteger
fun main(){ val a = AtomicInteger(0); println(a.incrementAndGet()) }
1
Kotlin использует те же классы JVM, поведение идентично Java.
// в среде с SharedArrayBuffer
const sab = new SharedArrayBuffer(4);
const ia = new Int32Array(sab);
ia[0] = 0;
// Atomics.add возвращает старое значение
const old = Atomics.add(ia, 0, 1);
const newVal = old + 1;
console.log(newVal);
1
Atomics.add возвращает старое значение, поэтому для поведения «инкремент и получить» требуется добавить 1 к возврату.
from threading import Lock
class AtomicInt:
def __init__(self, v=0):
self._v = v
self._lock = Lock()
def increment_and_get(self):
with self._lock:
self._v += 1
return self._v
ai = AtomicInt(0)
print(ai.increment_and_get())
1
В стандартной библиотеке нет чисто неблокирующего примитива; используются блокировки или внешние библиотеки.
// в обычном PHP нет атомарного примитива; в многопроцессных сценариях используются семафоры или расширения
// пример через синхронизацию в памяти опущен из-за различий окружений
(зависит от реализации)
Без расширений требуется внешняя синхронизация или использование механизмов БД/Redis.
В стандартной реализации Lua нет атомарных операций для общих переменных; для многопоточности применяются C-модули или среды с каналами.
-- PostgreSQL example
UPDATE counters SET value = value + 1 WHERE id = 1 RETURNING value;
value ------ 42
В базе данных операция выполняется транзакционно; поведение отличается по стоимости и семантике.
Типичные ошибки при использовании
- Ожидание глобальной атомарности нескольких операций
Если код выполняет две или более операций с разными атомарными переменными и требуется целостность, отдельные атомарные вызовы не дают транзакционной гарантии. Пример неверной логики:
AtomicInteger a = new AtomicInteger(0);
AtomicInteger b = new AtomicInteger(0);
// предположение: эти два инкремента должны считаться атомарно вместе
a.incrementAndGet();
b.incrementAndGet();
(нет гарантии атомарности двух операций вместе)
Инкремент после Integer.MAX_VALUE даёт отрицательное значение, что может сломать логику, если ожидается только рост.
AtomicInteger ai = null;
ai.incrementAndGet();
Exception in thread "main" java.lang.NullPointerException
Ожидание одинакового поведения у getAndIncrement() и incrementAndGet(). Различие в возвращаемом значении может привести к логическим ошибкам.
Изменения в API и истории
- Класс
AtomicIntegerи методincrementAndGet()существуют с Java 5. Сам метод не претерпевал функциональных изменений. - В Java 8 добавлены методы
updateAndGetиgetAndUpdate, позволяющие атомарно применять функцию обновления. - В Java 9 и выше появились
VarHandleкак более гибкая и низкоуровневая альтернативная API для операций с памятью и атомарностью. VarHandle даёт контроль над порядком памяти и может использоваться вместо атомиков в некоторых сценариях. - Для высококонкурентных счётчиков с Java 8 рекомендуется рассмотреть
LongAdder, который появился для повышения производительности в нагрузке с множеством потоков.
Расширенные примеры и нестандартные сценарии
1. Генератор уникальных идентификаторов с контролем переполнения
import java.util.concurrent.atomic.AtomicInteger;
public class IdGenerator {
private final AtomicInteger seq = new AtomicInteger(0);
private final int max;
public IdGenerator(int max){ this.max = max; }
public int nextId(){
int v = seq.incrementAndGet();
if (v > max){
// простой способ обработать переполнение: сброс с CAS
seq.compareAndSet(v, 0);
return 0;
}
return v;
}
}
// Пример использования
public class Main{
public static void main(String[] args){
IdGenerator g = new IdGenerator(3);
System.out.println(g.nextId()); // 1
System.out.println(g.nextId()); // 2
System.out.println(g.nextId()); // 3
System.out.println(g.nextId()); // 0 или 4 в зависимости от гонки
}
}
1 2 3 0
Пояснение: сброс через compareAndSet не гарантирует отсутствие гонок; для строгого поведения требуется более сложная логика.
2. Комбинация AtomicIntegerFieldUpdater для уменьшения накладных расходов объектов
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
class Task { volatile int state; }
public class UpdaterExample {
private static final AtomicIntegerFieldUpdater UPD =
AtomicIntegerFieldUpdater.newUpdater(Task.class, "state");
public static void main(String[] args){
Task t = new Task();
UPD.incrementAndGet(t);
System.out.println(t.state);
}
}
1
Пояснение: AtomicIntegerFieldUpdater позволяет атомарно обновлять примитивные поля в массивах объектов без выделения отдельного AtomicInteger для каждого объекта.
3. Сравнение с LongAdder в условиях высокой нагрузки
// Схематичный пример: в тесте с очень большим числом потоков LongAdder даёт лучшее масштабирование
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
// код замеряет время для AtomicInteger vs LongAdder при множественных инкрементах
(в реальном бенчмарке LongAdder обычно быстрее при высокой конкуренции)
Пояснение: LongAdder использует полями слотов и сводит число конфликтов CAS, поэтому итоговый time-to-complete часто меньше при сотнях потоков.
4. Сценарий условного приращения с retry через CAS
AtomicInteger ai = new AtomicInteger(0);
int expected, updated;
do {
expected = ai.get();
updated = (expected < 10) ? expected + 1 : expected;
} while (!ai.compareAndSet(expected, updated));
(если expected < 10, значение увеличится на 1; иначе останется)
Пояснение: пример показывает, как реализовать условный инкремент без блокировок, используя CAS в цикле.
5. Отладка некорректных ожиданий порядка операций
// Неправильное ожидание: два метода, использующие разные атомики, считаются синхронизованными
AtomicInteger a = new AtomicInteger(0);
AtomicInteger b = new AtomicInteger(0);
// поток1: a.incrementAndGet();
// поток2: if (b.get() > 0) doSomething();
(нет гарантии согласованного состояния между a и b)
Пояснение: атомарность относится к отдельной переменной; пересечение логики требует внешней синхронизации.
джава AtomicInteger.incrementAndGet() function comments
- джава AtomicInteger.incrementAndGet() - аргументы и возвращаемое значение
- Функция java AtomicInteger.incrementAndGet() - описание
- AtomicInteger.incrementAndGet() - примеры
- AtomicInteger.incrementAndGet() - похожие методы на java
- AtomicInteger.incrementAndGet() на javascript, c#, python, php
- AtomicInteger.incrementAndGet() изменения java
- Примеры AtomicInteger.incrementAndGet() на джава