Race Conditions in Kotlin
Race Conditions in Kotlin
A race condition occurs when the correctness of a program depends on the relative timing of concurrent operations accessing shared mutable state. Two or more threads or coroutines read and write the same data without proper synchronization, and the final result depends on which operation completes first. Race conditions produce bugs that are intermittent, difficult to reproduce, and often invisible during testing but surface under production load. By the end of this lesson, you will be able to:
- Explain how race conditions arise from unsynchronized access to shared mutable state.
- Identify the check then act and read modify write patterns as common race condition sources.
- Apply synchronization techniques in Kotlin including
synchronized,Mutex, and atomic operations. - Use coroutine confinement to eliminate shared mutable state in concurrent code.
How Race Conditions Occur
A race condition requires three ingredients: shared state, concurrent access, and at least one write operation. When two threads read a value, compute a new value based on it, and write back the result, the operations can interleave in ways that lose updates:
var counter = 0
fun increment() {
val current = counter // read
counter = current + 1 // write
}
If two threads call increment() simultaneously, both may read counter as 0, both compute 1, and both write 1. The counter ends up at 1 instead of 2. This is a read modify write race, and it happens because the read and write are not atomic.
Check Then Act Races
The other common pattern is check then act, where a condition is tested and an action is taken based on the result, but the condition may become invalid between the check and the action:
var balance = 100
fun withdraw(amount: Int): Boolean {
if (balance >= amount) { // check
balance -= amount // act
return true
}
return false
}
Two threads calling withdraw(80) concurrently may both see balance as 100, both pass the check, and both subtract 80, leaving the balance at negative 60. The check and the subtraction are not performed atomically.
Synchronization with synchronized
This interview continues for subscribers
Subscribe to Dove Letter for full access to exclusive interviews about Android and Kotlin development.
Become a Sponsor