← Назад к вопросам
Как исправить проблему гонки потоков за пару строк
2.0 Middle🔥 181 комментариев
#Многопоточность и асинхронность
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Как исправить проблему гонки потоков
Race condition (гонка потоков) — это ошибка, которая возникает, когда несколько потоков одновременно обращаются и изменяют общий ресурс без синхронизации, что приводит к непредсказуемому поведению.
Пример проблемы
var counter = 0
fun increment() {
counter++ // не потокобезопасно!
}
Thread { repeat(1000) { increment() } }.start()
Thread { repeat(1000) { increment() } }.start()
// Результат может быть 1000, 1500 или 2000 (случайно)
Решение 1: Synchronized блок
Самый простой и быстрый способ — использовать синхронизацию:
var counter = 0
fun increment() {
synchronized(this) {
counter++ // теперь потокобезопасно
}
}
Решение 2: Atomic переменная
Для простых операций используй AtomicInteger:
val counter = AtomicInteger(0)
fun increment() {
counter.incrementAndGet() // потокобезопасно
}
Решение 3: Volatile (не полное решение)
Если нужна только видимость изменений между потоками:
@Volatile
var counter = 0
Решение 4: Coroutines (для Android)
Используй Single-threaded Dispatcher:
val counterDispatcher = Dispatchers.Default.limitedParallelism(1)
var counter = 0
fun increment() = viewModelScope.launch(counterDispatcher) {
counter++ // безопасно в рамках этого диспетчера
}
Решение 5: Mutex (Kotlin Coroutines)
Для асинхронного кода:
val mutex = Mutex()
var counter = 0
suspend fun increment() {
mutex.withLock {
counter++
}
}
Лучший подход в Android
Используй Coroutines с Main Dispatcher для UI обновлений:
class CounterViewModel : ViewModel() {
private val _counter = MutableLiveData(0)
val counter: LiveData<Int> = _counter
fun increment() {
viewModelScope.launch {
val current = _counter.value ?: 0
_counter.value = current + 1 // автоматически на Main потоке
}
}
}
Выбор решения
- synchronized: для простого кода, не требующего производительности
- AtomicInteger: для примитивных типов с частыми обновлениями
- Coroutines: для современного Android кода
- Mutex: для асинхронного кода с Flow/StateFlow
Важно помнить: правильная архитектура (separation of concerns) часто исключает race conditions в корне.