Что такое гонка данных (Data Race) в многопоточности?

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

Ответ

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

Почему это происходит? Операции, которые кажутся атомарными (например, инкремент count++), на уровне процессора распадаются на несколько инструкций (чтение, изменение, запись). Потоки могут "пересекаться" на этих этапах.

Пример на Java:

class UnsafeCounter {
    private int count = 0;
    public void increment() {
        count++; // НЕ атомарная операция!
    }
    public int getCount() { return count; }
}
// Запуск двух потоков, вызывающих increment() 1000 раз каждый,
// может дать результат меньше 2000 из-за потерь обновлений.

Способы предотвращения:

  1. Синхронизация: Использование synchronized метода или блока.
    public synchronized void increment() { count++; }
  2. Атомарные типы из java.util.concurrent.atomic.
    private AtomicInteger count = new AtomicInteger(0);
    public void increment() { count.incrementAndGet(); }
  3. Иммутабельность: Использование неизменяемых объектов.
  4. Ограничение видимости: Локальные переменные или ThreadLocal.

Важно: Гонка данных — это проблема корректности, а не просто производительности.