Что такое состояние гонки (Race Condition) в многопоточности?

«Что такое состояние гонки (Race Condition) в многопоточности?» — вопрос из категории Java Core, который задают на 24% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Состояние гонки (Race Condition) — это ошибка проектирования многопоточной системы, при которой конечный результат выполнения зависит от непредсказуемого порядка выполнения или времени операций в параллельных потоках. Это происходит, когда несколько потоков обращаются к общим данным, и хотя бы одна операция является записывающей.

Классический пример — инкремент без синхронизации:

class UnsafeCounter {
    private int count = 0;
    public void increment() {
        count++; // НЕ атомарная операция: READ -> MODIFY -> WRITE
    }
    public int getCount() { return count; }
}

Потенциальный сценарий сбоя:

  1. Поток A читает count = 0.
  2. Поток B также читает count = 0.
  3. Оба потока увеличивают значение на 1.
  4. Поток A записывает count = 1.
  5. Поток B записывает count = 1.

Итог: После двух вызовов increment() ожидается count = 2, но получаем count = 1.

Способы решения:

  1. Синхронизация (synchronized):
    public synchronized void increment() {
        count++;
    }
  2. Атомарные классы из java.util.concurrent.atomic:
    import java.util.concurrent.atomic.AtomicInteger;
    class SafeCounter {
        private AtomicInteger count = new AtomicInteger(0);
        public void increment() {
            count.incrementAndGet(); // Атомарная операция
        }
    }
  3. Использование замков (Lock).

Ключевой принцип: Для предотвращения состояния гонки доступ к общим изменяемым данным должен быть правильно синхронизирован.