Concurrency
Concurrency primitives, patterns, and pitfalls in distributed systems.
Concurrency vs Parallelism
Concurrency is structuring a program to handle multiple tasks — they may interleave on a single core. Parallelism is executing multiple tasks simultaneously on multiple cores.
A concurrent program can run in parallel, but doesn't have to. A Go program with goroutines is concurrent; running it on 8 cores makes it parallel.
Threading Models
OS Threads (1:1)
Each language-level thread maps to one OS thread. Simple but expensive — each thread uses ~1MB stack space and context switches are costly.
Green Threads (M:N)
Many lightweight threads multiplexed onto fewer OS threads. Used by Go (goroutines), Erlang (processes), and Java (virtual threads in Project Loom).
Event Loop (1:N)
A single thread handles many connections using non-blocking I/O and callbacks. Used by Node.js, Nginx. Great for I/O-bound work, poor for CPU-bound.
Synchronization Primitives
Mutex (Mutual Exclusion)
Only one thread can hold the lock at a time. Protects critical sections.
Semaphore
A counter-based lock allowing up to N concurrent accesses. Useful for connection pools or rate limiting.
Read-Write Lock
Multiple readers can hold the lock simultaneously, but writers get exclusive access. Optimizes for read-heavy workloads.
Deadlock
A deadlock occurs when threads are stuck waiting for each other forever. Four conditions must all hold (Coffman conditions):
Prevention: break any one condition. Most common: always acquire locks in a consistent order (breaks circular wait).
Concurrency Patterns
Producer-Consumer
Producers add items to a bounded queue; consumers take items. The queue decouples production rate from consumption rate. Use when workloads are bursty.
Actor Model
Each actor is an isolated unit with its own state, processing messages sequentially from a mailbox. No shared state, no locks. Communication is purely through async messages. Used by Erlang/OTP, Akka.
Compare-and-Swap (CAS)
A lock-free atomic operation: update a value only if it matches an expected value. Foundation of lock-free data structures. Hardware-supported on modern CPUs.
Optimistic vs Pessimistic Concurrency
| Approach | Mechanism | Best For |
|---|---|---|
| Pessimistic | Lock before access | High contention, short critical sections |
| Optimistic | Detect conflicts at commit | Low contention, read-heavy workloads |
Databases use both: SELECT ... FOR UPDATE (pessimistic) vs version columns with conditional updates (optimistic).