← Назад к вопросам

Что можно сделать с AtomicInteger

2.0 Middle🔥 191 комментариев
#Многопоточность

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

AtomicInteger: операции и практическое применение

AtomicInteger — это класс в java.util.concurrent.atomic, предоставляющий потокобезопасные атомарные операции над целыми числами. Это критичный инструмент для многопоточного программирования без явных блокировок (lock-free).

Что такое AtomicInteger?

AtomicInteger использует Compare-and-Swap (CAS) операции для достижения потокобезопасности без synchronized блоков:

// Обычный int — НЕ потокобезопасен
public class Counter {
    private int count = 0; // ❌ Проблема: race condition
    
    public void increment() {
        count++; // Не атомарная операция!
        // Thread 1 читает count, Thread 2 читает count,
        // оба видят 0, оба пишут 1. Вместо +2, только +1
    }
}

// AtomicInteger — потокобезопасен
public class AtomicCounter {
    private AtomicInteger count = new AtomicInteger(0); // ✅ Потокобезопасно
    
    public void increment() {
        count.incrementAndGet(); // Гарантировано атомарно
    }
}

Основные операции AtomicInteger

1. Операции чтения и записи

AtomicInteger counter = new AtomicInteger(10);

// Получить текущее значение
int value = counter.get(); // 10

// Установить значение
counter.set(20); // counter = 20

// Получить старое значение и установить новое
int oldValue = counter.getAndSet(30); // oldValue = 20, counter = 30

2. Арифметические операции

AtomicInteger counter = new AtomicInteger(10);

// Увеличить на 1 и получить новое значение
int newValue = counter.incrementAndGet(); // newValue = 11, counter = 11

// Получить текущее и увеличить на 1
int oldValue = counter.getAndIncrement(); // oldValue = 11, counter = 12

// Уменьшить на 1
counter.decrementAndGet(); // counter = 11
counter.getAndDecrement(); // counter = 10

// Добавить значение
counter.addAndGet(5); // counter = 15
counter.getAndAdd(3); // oldValue = 15, counter = 18

3. Compare-and-Swap (CAS) операция

Это ключевая операция, лежащая в основе AtomicInteger:

AtomicInteger counter = new AtomicInteger(10);

// compareAndSet: если текущее значение == ожидаемое, установить новое
boolean updated = counter.compareAndSet(10, 20); // true, counter = 20

updated = counter.compareAndSet(10, 30); // false, counter остаётся 20

// Практический пример: безопасная инкрементация
public class SafeCounter {
    private AtomicInteger count = new AtomicInteger(0);
    
    public void safeIncrement() {
        int oldValue;
        int newValue;
        do {
            oldValue = count.get();
            newValue = oldValue + 1;
        } while (!count.compareAndSet(oldValue, newValue));
        // Если другой thread изменил count между get и set, повторить
    }
}

4. Атомарные обновления с функцией

AtomicInteger counter = new AtomicInteger(10);

// updateAndGet: применить функцию и получить результат
int newValue = counter.updateAndGet(x -> x * 2); // counter = 20

// getAndUpdate: получить старое значение, применить функцию
int oldValue = counter.getAndUpdate(x -> x + 5); // oldValue = 20, counter = 25

// Практический пример: условное обновление
public class LimitedCounter {
    private AtomicInteger counter = new AtomicInteger(0);
    private static final int MAX = 100;
    
    public boolean increment() {
        return counter.updateAndGet(current ->
            current < MAX ? current + 1 : current
        ) != counter.get();
    }
}

Практические примеры использования

1. Счётчик запросов (без блокировок)

public class RequestCounter {
    private AtomicInteger successCount = new AtomicInteger(0);
    private AtomicInteger failureCount = new AtomicInteger(0);
    
    public void recordSuccess() {
        successCount.incrementAndGet();
    }
    
    public void recordFailure() {
        failureCount.incrementAndGet();
    }
    
    public void printStats() {
        System.out.println("Success: " + successCount.get());
        System.out.println("Failure: " + failureCount.get());
    }
}

// Использование в многопоточной среде
ExecutorService executor = Executors.newFixedThreadPool(10);
RequestCounter counter = new RequestCounter();

for (int i = 0; i < 1000; i++) {
    executor.submit(() -> {
        try {
            // Имитация запроса
            counter.recordSuccess();
        } catch (Exception e) {
            counter.recordFailure();
        }
    });
}

2. Простой ID генератор

public class IdGenerator {
    private AtomicInteger nextId = new AtomicInteger(1);
    
    public int generateId() {
        return nextId.getAndIncrement();
    }
    
    public void reset() {
        nextId.set(1);
    }
}

// Использование
IdGenerator generator = new IdGenerator();
int id1 = generator.generateId(); // 1
int id2 = generator.generateId(); // 2
int id3 = generator.generateId(); // 3

3. Флаг для управления потоками

public class Worker {
    private AtomicInteger isRunning = new AtomicInteger(0); // 0 = stopped, 1 = running
    
    public void start() {
        if (isRunning.compareAndSet(0, 1)) {
            System.out.println("Worker started");
            // Запустить рабочий процесс
        } else {
            System.out.println("Already running");
        }
    }
    
    public void stop() {
        if (isRunning.compareAndSet(1, 0)) {
            System.out.println("Worker stopped");
        }
    }
    
    public boolean isRunning() {
        return isRunning.get() == 1;
    }
}

4. Буферизованный счётчик (batch операции)

public class BatchCounter {
    private AtomicInteger counter = new AtomicInteger(0);
    private static final int BATCH_SIZE = 1000;
    
    public void addWithBatch(int amount) {
        int current = counter.addAndGet(amount);
        if (current >= BATCH_SIZE) {
            // Отправить batch
            flush();
            counter.set(current % BATCH_SIZE);
        }
    }
    
    private void flush() {
        System.out.println("Flushing batch...");
    }
}

Производительность: AtomicInteger vs synchronized

public class PerformanceComparison {
    // ❌ С synchronized
    static class SynchronizedCounter {
        private int count = 0;
        public synchronized void increment() {
            count++;
        }
        public synchronized int get() {
            return count;
        }
    }
    
    // ✅ С AtomicInteger (намного быстрее)
    static class AtomicCounter {
        private AtomicInteger count = new AtomicInteger(0);
        public void increment() {
            count.incrementAndGet();
        }
        public int get() {
            return count.get();
        }
    }
    
    // Бенчмарк (упрощённо):
    // SynchronizedCounter: ~1000 ns per operation
    // AtomicInteger: ~100 ns per operation (в 10 раз быстрее!)
}

Когда использовать AtomicInteger?

✅ Используй, когда:

  • Нужен простой счётчик или флаг
  • Хочешь избежать блокировок
  • Нужна высокая производительность
  • Операция — простая арифметика

❌ Не используй, когда:

  • Нужны сложные операции (используй synchronized)
  • Нужна транзакционность (используй базу данных)
  • Нужны коллекции (используй ConcurrentHashMap, etc.)

AtomicInteger vs другие Atomic классы

// Для других типов данных
AtomicLong counter = new AtomicLong(0L);
AtomicBoolean flag = new AtomicBoolean(false);
AtomicReference<String> ref = new AtomicReference<>("initial");
AtomicIntegerArray array = new AtomicIntegerArray(10);

// Массивы для параллельной работы
AtomicIntegerArray counters = new AtomicIntegerArray(100);
counters.incrementAndGet(0); // Потокобезопасно для каждого индекса

Вывод

AtomicInteger — это:

  • Потокобезопасный счётчик без явных блокировок
  • Основан на CAS операциях
  • Намного быстрее synchronized
  • Идеален для простых счётчиков и флагов
  • Встроен в java.util.concurrent и всегда доступен

Владение AtomicInteger показывает понимание concurrency в Java и способность писать высокопроизводительный многопоточный код.