Skip to content

Concurrency Primitives — Notes#

Hierarchy of preferences (easiest → hardest to get right)#

  1. Make it immutable — share without locks.
  2. Make it thread-confined — only one thread touches it.
  3. Use a higher-level construct (BlockingQueue, ConcurrentMap, Actor, Channel).
  4. Use atomics or CAS for single-word state.
  5. Use a mutex / RW lock for compound state.
  6. 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.