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

В чем разница между Atomic и Synchronized?

1.7 Middle🔥 251 комментариев
#JVM и управление памятью#Многопоточность

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

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

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

# Атомарные операции vs Synchronized: подробный анализ

Основные различия

Synchronized — это встроенный механизм блокировки (монитор) на уровне объекта, который полностью сериализует доступ к критическим секциям. Atomic классы (AtomicInteger, AtomicLong, AtomicReference) используют безблокировочные (lock-free) алгоритмы на основе CAS (Compare-And-Swap) операций.

Детальное сравнение

Synchronized

public class Counter {
    private int count = 0;
    
    public synchronized void increment() {
        count++;
    }
    
    public synchronized int getCount() {
        return count;
    }
}

Как работает:

  • Каждый поток, вызвавший synchronized метод, должен получить монитор (lock) объекта
  • Остальные потоки блокируются (ждут в очереди) до освобождения монитора
  • Гарантирует полную exlusive access к критической секции
  • Может привести к контенции (争竞) при высокой нагрузке

Atomic классы

public class Counter {
    private AtomicInteger count = new AtomicInteger(0);
    
    public void increment() {
        count.incrementAndGet();
    }
    
    public int getCount() {
        return count.get();
    }
}

Как работает:

  • Использует CAS (Compare-And-Swap) команды процессора
  • Нет явной блокировки — поток повторяет CAS операцию, пока не успеет
  • При низкой контенции работает быстрее synchronized
  • Потокобезопасен на уровне отдельной переменной

Ключевые отличия

ХарактеристикаSynchronizedAtomic
МеханизмМонитор (блокировка)CAS (безблокировочный)
Производительность при низкой контенцииХорошоОтлично
Производительность при высокой контенцииМожет быть лучше (переходит в оптимизированный режим)Хуже (busy-waiting)
Область видимостиЛюбые переменные в блокеТолько одна переменная
Код в критической секцииМожет быть любымТолько атомарная операция
Memory visibilityJMM гарантируетГарантирует (volatile семантика)
Скорость контекстного переключенияМожет быть медленнееОбычно быстрее

Практические примеры

Когда использовать Synchronized:

// Когда нужно защитить несколько переменных
public synchronized void transfer(Account to, int amount) {
    this.balance -= amount;  // Переменная 1
    to.balance += amount;     // Переменная 2
}

// Сложная логика в критической секции
public synchronized void complexOperation() {
    if (condition) {
        // множество операций
    }
}

Когда использовать Atomic:

// Простая операция с одной переменной
AtomicInteger requestCount = new AtomicInteger(0);
requestCount.incrementAndGet();

// Высокая контенция, низкие задержки критичны
AtomicReference<User> cachedUser = new AtomicReference<>();
cachedUser.set(newUser);

Performance Trade-offs

Synchronized:

  • При низкой контенции: HotSpot компилятор применяет оптимизации (lock elision, escape analysis)
  • При высокой контенции: потоки блокируются, что может быть даже лучше, чем busy-waiting

Atomic:

  • При низкой контенции: очень быстро, нет context switch
  • При высокой контенции: может деградировать (CAS в цикле теряет эффективность)

Visibility гарантии

Оба подхода гарантируют happens-before отношения:

  • Synchronized: unlock → lock
  • Atomic: операция атомарно с volatile семантикой
// Оба примера безопасны в плане видимости изменений
AtomicInteger x = new AtomicInteger(0);
x.set(10);  // Гарантировано видно для всех потоков

synchronized(lock) {
    x = 10;  // Тоже гарантировано видно
}

Рекомендации

  1. Используй Atomic для простых счётчиков и флагов в многопоточной среде
  2. Используй Synchronized для защиты инвариантов над несколькими переменными
  3. Рассмотри StampedLock для читающих операций при высокой контенции
  4. Профилируй перед оптимизацией — не угадывай, измеряй
  5. Используй ConcurrentHashMap, CopyOnWriteArrayList вместо синхронизированных коллекций

Заключение

Выбор между Atomic и Synchronized зависит от сценария:

  • Если нужна простая операция с одной переменной → Atomic
  • Если нужна логика над несколькими переменными → Synchronized
  • Если критична производительность → профилируй и измеряй
  • Для современного кода предпочитай конкурентные структуры данных (java.util.concurrent.*)
В чем разница между Atomic и Synchronized? | PrepBro