Concurrency is the ability to execute multiple tasks in overlapping time periods, while parallelism executes multiple tasks simultaneously on multiple cores or processors. These concepts are fundamental to building performant, responsive software systems that leverage modern multi-core hardware. The key challenge lies not in spawning threads or processes, but in coordinating their access to shared resources without introducing subtle, hard-to-reproduce bugs. Understanding the distinction between concurrency models (threads, processes, coroutines, virtual threads), synchronization primitives (mutexes, semaphores, barriers), and common pitfalls (race conditions, deadlocks, false sharing) transforms concurrent programming from an intimidating minefield into a structured engineering discipline with predictable trade-offs and proven patterns.
What This Cheat Sheet Covers
This topic spans 11 focused tables and 92 indexed concepts, 91 flashcards. Below is a complete table-by-table outline of this topic, spanning foundational concepts through advanced details.
A jump-to index of every table row in this cheat sheet.
An interactive map of every table and concept in this topic.
Table 1: Concurrency Models
Concurrency and parallelism are realized through a variety of execution units β each with different scheduling, memory, and overhead characteristics. Choosing the right model up-front determines everything from thread-safety surface area to scalability ceiling.
| Model | Example | Description | |
|---|---|---|---|
std::thread t(func);t.join(); | β’ OS-managed execution unit sharing process memory space β’ preemptively scheduled by kernel β’ ~1MB stack overhead per thread β’ suitable for CPU-bound parallel work. | ||
fork() in Unixmultiprocessing.Process() in Python | β’ Independent execution unit with separate memory space β’ isolated from other processes β’ higher creation/context-switch cost β’ communicates via IPC β’ avoids shared-memory race conditions. | ||
async def fetch(): await http.get(url) | β’ Cooperatively-scheduled function that can suspend and resume execution β’ lightweight (~KB overhead) β’ ideal for I/O-bound tasks β’ requires explicit yield points β’ avoids preemption overhead. | ||
go func() { ... }() | β’ Go's lightweight threads managed by Go runtime β’ multiplexed onto OS threads (M:N model) β’ starts with 2KB stack that grows dynamically β’ extremely cheap to spawn thousands. | ||
Thread.startVirtualThread( () -> blockingOp());Executors.newVirtualThreadPerTaskExecutor() | β’ JVM-managed lightweight thread (Java 21+, JEP 444) that unmounts from its OS carrier thread during blocking β’ millions can run concurrently on modest hardware β’ enables thread-per-task style without reactive complexity for I/O-bound workloads | ||
Akka, Erlang OTP | β’ Message-passing concurrency where actors are isolated units that communicate via asynchronous messages β’ no shared state β’ inherently avoids many concurrency bugs β’ scales naturally to distributed systems. | ||
Node.js, JavaScript async | β’ Single-threaded with non-blocking I/O β’ events processed sequentially from queue β’ eliminates race conditions but CPU-bound tasks block entire loop β’ combines with async/await for readability. | ||
Erlang processes, early Java threads | β’ User-space threads scheduled by runtime/VM rather than OS β’ many-to-one or many-to-many mapping to OS threads β’ lower overhead but cannot utilize multiple cores without runtime support. | ||
boost::fiber in C++CreateFiber() in Windows | β’ User-mode cooperative scheduling primitive β’ explicit context switching β’ ultra-lightweight β’ useful for high-concurrency scenarios like game engines or network servers. |