We break down three “anti-progress” patterns in concurrent Kotlin-coroutines code:
deadlock (mutual waiting),
livelock (busy activity with no outcome), and
starvation (tasks getting starved). Using examples with
Mutex,
withLock, and
tryLock(), we show how mistakes grow out of lock-acquisition order, overly long critical sections, and “polite” retries—and then we fix them with rules: a single order by
id, a short
withLock, backoff, and (when possible) a switch to
confinement/
actor design.