Как ответить
Race condition (состояние гонки) — это дефект в многопоточной или асинхронной программе, при котором результат выполнения зависит от непредсказуемого порядка или времени выполнения потоков. Проще говоря, два или более потока одновременно обращаются к общему ресурсу (память, файл, сокет) без должной синхронизации, и финальное состояние этого ресурса определяется тем, какой поток завершит операцию последним.
Классический пример — инкремент счётчика. Операция counter++ на уровне процессора состоит из трёх шагов: чтение из памяти, увеличение, запись обратно. Если два потока выполнят эти шаги вперемешку, мы потеряем одно увеличение:
// Изначально counter = 0
// Поток A: читает counter (0), готовится записать 1
// Поток B: читает counter (0), готовится записать 1
// Поток A: записывает 1
// Поток B: записывает 1
// Итог: counter = 1, хотя ожидалось 2В реальных проектах race condition может проявляться в:
- Кэшах без блокировок (Lazy Initialization) — два потока одновременно проверяют
if (cache == null)и создают два экземпляра объекта. - Сборке данных из нескольких источников — например, при обновлении UI из фоновых потоков без Dispatcher.
- Работе с коллекциями в .NET/Java без синхронизации —
ConcurrentModificationExceptionили пропажа элементов.
Основные методы борьбы:
- Блокировки (locks) —
lockв C#,synchronizedв Java, мьютексы в Go. Минус — риск дедлоков и падение производительности. - Атомарные операции —
Interlocked.Incrementв .NET,AtomicIntegerв Java. Работают быстрее блокировок, но подходят только для простых операций. - Неблокирующие структуры данных — ConcurrentDictionary, ConcurrentQueue. Используют CAS (Compare-And-Swap) на уровне процессора.
- Изоляция (STM, Actor Model) — каждый поток работает с копией данных, изменения сливаются позже. Применяется в Erlang, Clojure.
На практике race condition — одна из самых сложных для отладки проблем: она может воспроизводиться раз в 10 000 запусков. Инструменты поиска: ThreadSanitizer (C++), JetBrains dotMemory (для .NET), Java Flight Recorder. В коде помогает простая дисциплина: если переменная используется из нескольких потоков — либо она неизменяемая (immutable), либо защищена блокировкой, либо атомарна.