Ответ
Примитивные типы (int, long, boolean и др.) не являются объектами, но их можно сделать потокобезопасными с помощью следующих механизмов:
1. Атомарные классы (java.util.concurrent.atomic) — НАИБОЛЕЕ РЕКОМЕНДУЕМЫЙ СПОСОБ Они оборачивают примитив и предоставляют атомарные операции.
AtomicInteger counter = new AtomicInteger(0);
// Все операции атомарны и потокобезопасны
counter.incrementAndGet(); // Аналог ++i
counter.addAndGet(10); // Аналог i += 10
boolean updated = counter.compareAndSet(11, 20); // CAS-операция
Доступны: AtomicInteger, AtomicLong, AtomicBoolean, AtomicReference (для объектов).
2. Ключевое слово volatile
Гарантирует видимость изменений между потоками, но НЕ атомарность составных операций (например, i++).
private volatile int sharedFlag = 0;
// Поток 1:
sharedFlag = 1; // Изменение сразу станет видно другим потокам
// Поток 2:
if (sharedFlag == 1) { // Увидит актуальное значение
// Действие
}
Не подходит для операций типа «прочитать-изменить-записать» (read-modify-write).
3. Синхронизация (synchronized)
Обеспечивает и атомарность, и видимость, но с накладными расходами на блокировку.
private int counter = 0;
public synchronized void increment() {
counter++; // Теперь операция атомарна
}
public synchronized int get() {
return counter;
}
| Сравнение и рекомендации: | Подход | Атомарность i++ |
Производительность | Сценарий использования |
|---|---|---|---|---|
AtomicInteger |
Да (через CAS) | Очень высокая | Частые атомарные обновления в многопоточной среде. | |
volatile |
Нет | Высокая | Флаги, одноразовые записи, публикация готовых объектов (safe publication). | |
synchronized |
Да | Ниже (блокировка) | Сложные критические секции, где несколько операций должны выполняться как одна. |
Вывод: Для простых атомарных операций над примитивами всегда предпочитайте атомарные классы.