Concurrency
Threads on the JVM share common memory, and all the difficulty is in coordinating access to it. Kotlin here relies on the JVM model: a monitor (synchronized) provides mutual exclusion, wait/notify provide coordination, and the Java Memory Model (JMM) describes what one thread is guaranteed to see of another's writes. Forgetting any of these layers means a data race, a deadlock, or an invisible write.
The treachery is that such bugs are non-deterministic: code can "work" for years until a change of hardware or load shifts the timing. So concurrency is understood not by "it worked" but by the rules — what a monitor guarantees, what @Volatile guarantees, when a deadlock arises, and why an object leaks while staying reachable from a GC root. The full map is in the layers below.
Topic map
- Monitor and synchronized — mutual exclusion through an object's monitor and what
synchronizedprotects. - wait and notify — how threads coordinate by releasing the monitor while waiting.
- Deadlock — the four deadlock conditions and how two threads freeze forever.
- Lock ordering — a single global order as a way to rule out deadlock.
- The Java Memory Model — why one thread's write may be invisible to another and
[0, 0]is legal. - The happens-before relation — what provides the visibility and ordering guarantee.
- Visibility and volatile — what
@Volatileguarantees and what it does not. - Memory leaks — reachability from a GC root,
innerclasses, andWeakReference.
Common traps
| Mistake | Consequence |
|---|---|
Thinking synchronized releases the monitor between loop iterations | The thread holds the monitor the whole loop — the other starves, an effective deadlock |
| Acquiring two locks in a different order in different threads | Circular wait and a deadlock |
| Assuming a write is visible to other threads instantly | Without happens-before a write may not be visible at all |
Believing @Volatile makes count++ atomic | @Volatile gives visibility but not atomicity — the update is lost |
Blaming WeakReference instead of the implicit inner-class reference | The real leak is the strong this$0 reference to the outer object |
| Expecting the OS scheduler to break the deadlock itself | A deadlock is forever — it must be ruled out by lock ordering |
Interview relevance
Concurrency is a favourite screening topic: it shows whether you separate "visibility" from "atomicity", a monitor from a lock, and whether you grasp that a bug can be non-deterministic. A candidate who says "@Volatile is about visibility, synchronized is about mutual exclusion, deadlock is about circular wait" immediately gets ahead of one who dumps everything into "well, there's a race".
Typical checks:
- What
synchronizedprotects and why the monitor is held for the whole block. - How
wait/notifycoordinate threads and why they are called under the monitor. - The four deadlock conditions and how a single lock order rules it out.
- What
@Volatileguarantees (visibility) and what it does not (atomicity ofcount++). - Why
[0, 0]is possible without barriers and what happens-before is. - Why an object leaks while staying reachable, and how
WeakReferencehelps.
Common wrong answer: "@Volatile makes operations atomic, so the counter is thread-safe". In fact @Volatile guarantees only visibility and ordering, but count++ is a read-increment-write, and two threads still lose an update; for atomicity you need synchronized or AtomicInteger.