Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
# Atomic типы в Java
Atomic типы — это набор потокобезопасных классов из пакета java.util.concurrent.atomic, предоставляющих атомарные операции над примитивными типами данных и объектами без явной синхронизации.
Основное назначение
Atomic типы нужны для:
- Потокобезопасности без locks — операции выполняются атомарно без блокировок
- Высокой производительности — CAS (Compare-And-Swap) операции быстрее чем synchronized
- Простоты кода — более читаемо, чем synchronized блоки
- Избежания deadlocks — нет явных блокировок, поэтому нет возможности deadlock
Семейство Atomic типов
1. AtomicInteger
Атомарная переменная целого типа int:
AtomicInteger counter = new AtomicInteger(0);
// Базовые операции
counter.get(); // Получить значение
counter.set(5); // Установить значение
// Атомарные операции
counter.incrementAndGet(); // ++counter, вернуть новое
counter.decrementAndGet(); // --counter, вернуть новое
counter.getAndIncrement(); // counter++, вернуть старое
counter.getAndDecrement(); // counter--, вернуть старое
// Операции с другими значениями
counter.addAndGet(10); // counter += 10, вернуть новое
counter.getAndAdd(10); // counter += 10, вернуть старое
// Compare-And-Swap
counter.compareAndSet(5, 20); // Установить 20 если текущее == 5
// Обновить если меньше/больше
counter.accumulateAndGet(5, Integer::max); // max(5, current)
counter.accumulateAndGet(5, Integer::min); // min(5, current)
2. AtomicLong
Атомарная переменная длинного целого типа long:
AtomicLong timestamp = new AtomicLong(System.currentTimeMillis());
timestamp.incrementAndGet();
timestamp.addAndGet(1000);
// Полезна для счетчиков в масштабе (большие числа)
AtomicLong totalRequests = new AtomicLong(0);
totalRequests.incrementAndGet();
3. AtomicBoolean
Атомарная переменная логического типа boolean:
AtomicBoolean isRunning = new AtomicBoolean(true);
if (isRunning.get()) {
isRunning.set(false);
}
// CAS для флагов
boolean oldValue = isRunning.getAndSet(true);
// Использование в условиях
if (!isRunning.compareAndSet(true, false)) {
System.out.println("Уже остановлено");
}
4. AtomicReference<T>
Атомарная ссылка на объект любого типа:
class User {
String name;
int age;
}
AtomicReference<User> userRef = new AtomicReference<>(new User());
// Получить и установить
User user = userRef.get();
userRef.set(new User());
// CAS для объектов
User expectedUser = userRef.get();
UserRef.compareAndSet(expectedUser, new User());
// Обновить объект атомарно
AtomicReference<StringBuilder> sb =
new AtomicReference<>(new StringBuilder("Hello"));
sb.updateAndGet(s -> {
s.append(" World");
return s;
});
5. AtomicIntegerArray
Массив атомарных int значений:
AtomicIntegerArray array = new AtomicIntegerArray(10);
// Операции с элементами массива
array.set(0, 5);
int value = array.get(0);
array.incrementAndGet(0);
array.addAndGet(1, 10);
// CAS для элемента
array.compareAndSet(0, 5, 20);
6. AtomicLongArray
Массив атомарных long значений:
AtomicLongArray array = new AtomicLongArray(10);
array.set(0, 1000000L);
array.addAndGet(0, 500000L);
7. AtomicReferenceArray<E>
Массив атомарных ссылок на объекты:
AtomicReferenceArray<String> array = new AtomicReferenceArray<>(5);
array.set(0, "Hello");
String value = array.get(0);
array.compareAndSet(0, "Hello", "World");
Практические примеры
Пример 1: Счетчик веб-запросов
public class WebAnalytics {
private AtomicLong totalRequests = new AtomicLong(0);
private AtomicLong successRequests = new AtomicLong(0);
private AtomicLong failedRequests = new AtomicLong(0);
public void recordRequest(boolean success) {
totalRequests.incrementAndGet();
if (success) {
successRequests.incrementAndGet();
} else {
failedRequests.incrementAndGet();
}
}
public void printStats() {
System.out.println("Total: " + totalRequests.get());
System.out.println("Success: " + successRequests.get());
System.out.println("Failed: " + failedRequests.get());
}
}
Пример 2: Управление потоком выполнения
public class WorkerThread extends Thread {
private AtomicBoolean shouldStop = new AtomicBoolean(false);
private AtomicLong processedItems = new AtomicLong(0);
@Override
public void run() {
while (!shouldStop.get()) {
// Обработать элемент
processItem();
processedItems.incrementAndGet();
}
}
public void stop() {
shouldStop.set(true);
}
public long getProcessedCount() {
return processedItems.get();
}
private void processItem() {
// Логика обработки
}
}
Пример 3: Безопасное кэширование объектов
public class CachedConnection {
private AtomicReference<DatabaseConnection> connection =
new AtomicReference<>();
public DatabaseConnection getConnection() {
DatabaseConnection conn = connection.get();
if (conn == null) {
DatabaseConnection newConn = new DatabaseConnection();
if (connection.compareAndSet(null, newConn)) {
return newConn;
} else {
// Другой поток создал соединение первым
return connection.get();
}
}
return conn;
}
}
Пример 4: Счетчик активных соединений
public class ConnectionPool {
private AtomicInteger activeConnections = new AtomicInteger(0);
private static final int MAX_CONNECTIONS = 100;
public boolean acquireConnection() {
int current = activeConnections.get();
if (current >= MAX_CONNECTIONS) {
return false;
}
return activeConnections.compareAndSet(current, current + 1);
}
public void releaseConnection() {
activeConnections.decrementAndGet();
}
public int getActiveConnections() {
return activeConnections.get();
}
}
Пример 5: Версионирование данных
public class VersionedData {
private AtomicReference<DataVersion> current =
new AtomicReference<>(new DataVersion(1, "initial"));
public DataVersion update(String newData) {
DataVersion oldVersion = current.get();
DataVersion newVersion = new DataVersion(
oldVersion.version + 1,
newData
);
if (current.compareAndSet(oldVersion, newVersion)) {
return newVersion;
} else {
// Другой поток обновил данные
return update(newData);
}
}
}
Compare-And-Swap (CAS) механизм
AtomicInteger counter = new AtomicInteger(5);
// CAS: если counter == 5, установить 10, вернуть true
boolean success = counter.compareAndSet(5, 10);
System.out.println(success); // true
// Попытка снова с 5
boolean success2 = counter.compareAndSet(5, 15);
System.out.println(success2); // false (значение уже 10)
// Правильный способ: loop until success
int expectedValue;
int newValue;
do {
expectedValue = counter.get();
newValue = expectedValue * 2;
} while (!counter.compareAndSet(expectedValue, newValue));
Производительность: Atomic vs Synchronized
// Синхронизированный счетчик (медленнее)
public class SyncCounter {
private int count = 0;
public synchronized void increment() { count++; }
public synchronized int get() { return count; }
}
// Atomic счетчик (быстрее)
public class AtomicCounter {
private AtomicInteger count = new AtomicInteger(0);
public void increment() { count.incrementAndGet(); }
public int get() { return count.get(); }
}
// Бенчмарк
public class PerformanceTest {
public static void main(String[] args) {
// AtomicCounter примерно в 2-3 раза быстрее
// в многопоточной среде благодаря CAS
}
}
Когда использовать Atomic типы
Используй Atomic для:
- Простых счетчиков
- Флагов управления потоками
- Кэширования одного объекта
- Low-contention сценариев (мало конкуренции)
- Высоконагруженных систем
Используй synchronized/Lock для:
- Сложной синхронизации нескольких переменных
- High-contention сценариев (много конкуренции)
- Защиты целого блока кода
- Когда нужна условная переменная (Condition)
Недостатки и ограничения
- Работают только с примитивами и одиночными объектами
- Не подходят для синхронизации нескольких переменных
- Могут быть неэффективны при очень высокой конкуренции
- Требуют понимания CAS операций
Atomic типы — это мощный инструмент для написания эффективного многопоточного кода с минимальной синхронизацией.