Concurrent code fails differently from everything else you write. It passes review, passes tests, runs for a year, then returns a wrong answer under load — the defect was never a bad line, it was a missing ordering rule in the design. This guide is about that shape: what a memory model promises, what a lock buys that an atomic does not, why deadlock always looks the same, and why the tools that catch these defects only catch the ones you ran. Concurrency semantics are language-specific, so every claim names its model.
Each chapter opens with the short version. Tap one to read the detail.
Concurrency is a structure; parallelism is a resource
~2 min
Threads exist so a program can use several cores, but nothing in a concurrency toolkit is about speed: mutexes, condition variables, semaphores and latches all exist to order and exclude. Extra cores do not create the hard problems.
A data race is a missing rule, not bad luck
~2 min
Go and Java define a data race identically: two accesses to one location, at least one a write, with nothing ordering them. Neither mentions clocks, cores or probability — a race is a design defect, not an accident you test away.
Atomicity, visibility and ordering are three different promises
~2 min
Java's volatile buys visibility and ordering; it does not make a read-then-write indivisible. The identically spelled C++ keyword buys neither — it is for memory-mapped hardware, not threads. Name the guarantee you need before grabbing a keyword.
Happens-before, and the deal it offers you
~2 min
A memory model does not say what will happen; it says which writes a read may observe. Go and Java offer one bargain: a race-free program can be reasoned about as a plain interleaving. Race, and the model owes you nothing.
Where edges come from: release, acquire, and the object they belong to
~2 min
Every cross-thread edge is a release paired with an acquire that actually reads what the release wrote, and it belongs to one object. A different mutex, channel or volatile field is a different edge — so "but it is locked" answers nothing.
One lock per invariant, not one per field
~2 min
A lock supplies exclusion and an ordering edge, but only against threads taking that same lock. If one rule spans two fields, one lock must span both. Semaphores, latches and barriers bound or rendezvous rather than protect.
Deadlock is a cycle, and cycles are preventable
~2 min
Deadlock is not bad luck: it is a cycle of threads each holding one lock and waiting for the next. Two remedies exist, both boring — take every multi-lock set in one stable order, or take the whole set atomically.
Waiting for a condition without losing the wakeup
~2 min
A condition variable is not a message you send and forget. The waiter must re-test its predicate in a loop, because a wait may return with no notification at all — and the writer must change the state under the mutex, even when it is atomic.
Atomics, compare and swap, and the cost of a shared cache line
~2 min
An atomic read modify write is one operation rather than a read plus a write, and it must see the latest value — which is what makes a retry loop work. What atomics never make cheap is sharing, because coherence moves whole cache lines.
Thread-safe pieces, unsafe wholes
~2 min
Making every method atomic makes every sequence of methods racy. That is why concurrent maps ship compound operations, why their size is documented as an estimate, and why their iterators never throw — they show state at or since creation, not a snapshot.
Running tasks, and actually stopping them
~2 min
A pool decouples tasks from threads, and its two sharpest edges share a shape: a failure nobody reads, and a shutdown nobody waits for. An exception inside a task is stored in its future and stays silent until someone calls get.
Suspending instead of blocking, passing instead of sharing
~2 min
A coroutine suspends by returning to its caller rather than holding a thread, which removes blocking but not races: shared state can change across every suspension point. Channels avoid shared state entirely, at the price of a new failure set.
Written by Keentune. We are not affiliated with or endorsed by the organizations whose documentation informs this guide, and any linked sources belong to their respective owners.
All exam, test, and product names and trademarks are the property of their respective owners and are used here for identification and reference only. Keentune is independent study practice — not affiliated with, authorized, or endorsed by any of these organizations.