Назад к вопросам
Middle
147
questionbank

Что такое атомарные типы данных и для чего они нужны?

Sobes Copilot

Получайте ответы в реальном времени

Ответ от нейросети

sobes.tech AI

Атомарные типы данных - это классы из пакета java.util.concurrent.atomic, предоставляющие примитивные типы и ссылки на объекты с атомарными (неделимыми) операциями. Они используются для безопасной работы с изменяемыми переменными в многопоточной среде без явного использования блокировок (например, с помощью synchronized).

Ключевые особенности:

  • Атомарность: Гарантируют, что операция над переменной выполняется полностью или не выполняется вообще, предотвращая состояние гонки.
  • Non-blocking: Большинство операций реализованы с использованием низкоуровневой инструкции Compare-And-Swap (CAS), которая не блокирует потоки.
  • Производительность: В случаях высокого уровня конкуренции могут быть более производительными, чем блокировки.
  • Volatile-like memory effects: Обладают свойствами видимости, схожими с ключевым словом volatile.

Примеры популярных атомарных типов:

  • AtomicBoolean
  • AtomicInteger
  • AtomicLong
  • AtomicReference
  • AtomicIntegerArray
  • AtomicLongArray
  • AtomicReferenceArray

Основные операции включают:

  • get(): Получить текущее значение.
  • set(newValue): Установить новое значение.
  • compareAndSet(expect, update): Атомарно установить значение update, если текущее значение равно expect.
  • getAndIncrement(): Атомарно увеличить значение на 1 и вернуть предыдущее значение.
  • incrementAndGet(): Атомарно увеличить значение на 1 и вернуть новое значение.

Необходимость атомарных типов возникает, когда требуется выполнять потокобезопасные операции над одиночными переменными без усложнения кода явными блокировками или риском возникновения взаимных блокировок.

import java.util.concurrent.atomic.AtomicInteger;

public class AtomicExample {

    public static void main(String[] args) throws InterruptedException {
        AtomicInteger counter = new AtomicInteger(0); // Использование атомарного типа

        Runnable task = () -> {
            for (int i = 0; i < 1000; i++) {
                counter.incrementAndGet(); // Атомарное увеличение
            }
        };

        Thread thread1 = new Thread(task);
        Thread thread2 = new Thread(task);

        thread1.start();
        thread2.start();

        thread1.join();
        thread2.join();

        System.out.println("Final counter value: " + counter.get()); // Результат будет 2000
    }
}