Concurrency Primitives — Notes
Hierarchy of preferences (easiest → hardest to get right)
- Make it immutable — share without locks.
- Make it thread-confined — only one thread touches it.
- Use a higher-level construct (BlockingQueue, ConcurrentMap, Actor, Channel).
- Use atomics or CAS for single-word state.
- Use a mutex / RW lock for compound state.
- Hand-roll lock-free algorithms — only if profiling shows you must.
Common bugs
- Race condition — observable result depends on interleaving.
- Deadlock — circular wait on locks.
- Livelock — threads remain active but make no progress.
- Starvation — a thread is perpetually denied access.
- ABA problem — CAS-related: pointer changes A→B→A; CAS thinks nothing happened.
- False sharing — two threads write to adjacent cache lines, causing coherence traffic.
Memory model
- Java:
volatile, synchronized, j.u.c.atomic.* give specific happens-before guarantees.
- C++: explicit memory_order on
std::atomic.
- Go: channels + sync package.
- Python: GIL serialises Python bytecode, but you still need locks for compound state.
Refs
- Java Concurrency in Practice — Brian Goetz.
- The Art of Multiprocessor Programming — Herlihy & Shavit.
- Doug Lea's
j.u.c rationale documents.
- Tony Van Eerd's "Lock-Free by Example" talks.