Представьте ситуацию: у вас на банковском счете 100$. Вы и ваша жена одновременно (в одну миллисекунду) пытаетесь снять 10$ через разные банкоматы.
В теории должно остаться 80$.
На практике, из-за Race Condition, может остаться 90$. Банк потерял деньги. 💸
Почему так происходит?
Даже простая операция
count++ (увеличение счетчика) для процессора - это три действия:1. Считать текущее значение (100).
2. Прибавить единицу (101).
3. Записать новое значение (101).
Если два потока начнут выполнять шаг 1 одновременно, они оба "увидят" 100. Оба прибавят 1 и запишут 101. Одно действие потеряется навсегда.
🐛 Heisenbug (Гейзенбаг):
Самое страшное в гонках то, что они часто исчезают, когда вы начинаете дебажить (добавляете
print или брейкпоинты), так как это меняет тайминги выполнения потоков.🛡 Как защититься (Инструменты Мидла):
🤖 Android (Kotlin):
🔵Atomic-типы: Для простых счетчиков используйте
AtomicInteger или AtomicBoolean. Они гарантируют атомарность операций.🔵Mutex (для Coroutines): Это "светофор" для корутин.
val mutex = Mutex()
mutex.withLock {
// Код здесь выполняется только одним потоком за раз
count++
}
• StateFlow: Позволяет безопасно обновлять состояние UI, избегая гонок.
🍏 iOS (Swift):
• Actors (Swift 5.5+): В 2026 году это стандарт. Акторы автоматически защищают свое изменяемое состояние. Вам не нужны ручные блокировки.
actor BankAccount {
var balance = 100
func withdraw(amount: Int) { balance -= amount }
}
• Serial Queues (GCD): Старая добрая очередь, где задачи выполняются строго по одной.
💡 Совет: Если у вас в приложении есть переменная
var, которую меняют из разных фоновых потоков, это бомба замедленного действия. Заверните её в Atomic, Mutex или Actor.Сталкивались с багами, которые невозможно повторить на устройстве разработчика? 👇
#concurrency #multithreading #android #ios #kotlin #swift #bugs
👉 @developer_mobila
