← Назад к вопросам

Как исправить проблему гонки потоков за пару строк

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 в корне.

Как исправить проблему гонки потоков за пару строк | PrepBro