Как решать проблемы race condition в Android разработке
Что проверяют
Знаете ли вы, где гонки возникают именно в Android: несколько корутин меняют одно состояние, ответы сети приходят не по порядку, колбэк срабатывает после уничтожения экрана. Следом обычно просят показать гонку во ViewModel и объяснить, почему synchronized плохо сочетается с корутинами.
Как отвечать
Сначала определение: результат зависит от порядка выполнения, потому что операция «прочитать, изменить, записать» не атомарна. Дальше случаи и инструменты современного стека на Kotlin:
- состояние в
StateFlow:_state.value = _state.value.copy(...)из двух корутин теряет одно из изменений, а_state.update { it.copy(...) }делает сравнение с обменом и повторяет попытку; - общий ресурс в корутинах:
MutexиwithLockприостанавливают корутину, а не блокируют поток. Вызвать suspend-функцию внутриsynchronizedкомпилятор не даст. Учтите, чтоMutexне реентерабельный; - ограничение параллелизма: всё изменение состояния на одном потоке через
Dispatchers.Default.limitedParallelism(1)или наDispatchers.Main; - устаревшие ответы: поиск по вводу через
flatMapLatestилиcollectLatest, отмена предыдущегоJobпри новом запросе, защита от двойного нажатия; - жизненный цикл: сбор потоков в
repeatOnLifecycle(Lifecycle.State.STARTED), работа вviewModelScope, чтобы она отменялась с экраном; - данные:
@TransactionиwithTransactionв Room, атомарныеupdateDataиeditв DataStore вместо пары чтение и запись вSharedPreferences; - простые счётчики:
AtomicInteger,ConcurrentHashMap.
Гонки тестируют через runTest и StandardTestDispatcher, где порядок корутин управляется явно.
Где спотыкаются
Путают гонку с обновлением интерфейса из фонового потока. Второе обычно сразу падает с CalledFromWrongThreadException, а гонка портит данные тихо и не каждый раз.
Не знают, что LiveData.postValue склеивает значения: если вызвать его несколько раз до того, как главный поток их обработает, наблюдатель получит только последнее.
Лечат всё через synchronized и Executors, как в Java-коде десятилетней давности, и игнорируют структурированную конкурентность и отмену корутин.