Concurrency Fundamentals
Concurrency is the structuring of a program so that multiple tasks can make progress within overlapping time periods. It covers threads, synchronization primitives, race conditions, deadlocks, and the models programmers use to coordinate shared mutable state safely.
itComputer fundamentals | OpenSkills.info
Course pathWalk it in order
Look it upDip in anytime
Go furtherLeaves this page
Don't Panic
Don't Panic: Concurrency Fundamentals
Concurrency is how a program keeps several independent activities moving while their lifetimes overlap. It exists because waiting is everywhere: networks, files, timers, background jobs, and other services all decline to finish on your preferred timetable. Before concurrency, one slow operation could hold the whole program hostage. The program has since acquired more guests, which is useful, but now someone must keep the guest list.
The first useful distinction is between concurrency and parallelism. Concurrency organizes overlapping work. Parallelism runs computations at the same instant and needs processor capacity. One core can interleave tasks without making them parallel. More workers can create more waiting, scheduling, and contention without creating more useful output. Physics remains regrettably firm on this point.
Shared mutable state is where the paperwork begins. If two tasks change the same value, the program needs an invariant: the condition that must stay true. A mutex can protect that invariant. A channel can give one task ownership and let the others send requests. Either way, source order alone does not tell another task which write it can observe. The memory model and a happens-before relationship provide that guarantee.
A bounded queue is not a decorative basket for work. It decides what happens when producers outpace consumers. Capacity, worker count, closure behavior, and failure path are part of the program's behavior. So is cancellation. A parent operation that tracks child tasks can stop unfinished work and wait for cleanup instead of leaving a background task wandering the corridors with a socket and an opinion.
Start with the Intro when the vocabulary needs a proper map. Use Slides for the relationships among ownership, ordering, and liveness. Keep the Cheatsheet close when choosing a primitive or diagnosing a stalled system. The Practice Reference turns the ideas into a bounded pipeline design. The Quiz checks the distinctions that tend to blur when work starts interleaving. Define ownership, bounds, completion, failure, and cancellation before asking the runtime to go faster.
Where this skill leads
Relevant careers
See how this topic contributes to broader role-level skill maps.
Sources
- https://go.dev/blog/waza-talk
Supports
- Concurrency composes independently executing activities
- Parallelism is simultaneous execution of computations
- Concurrency and parallelism are related but distinct
- https://go.dev/ref/mem
Supports
- A data race involves conflicting access to the same memory location without the required synchronization
- Happens-before combines sequenced and synchronized ordering
- Channels, mutexes, initialization, and atomic operations provide documented synchronization effects
- Data-race-free Go executions have sequentially consistent outcomes
- https://docs.oracle.com/javase/specs/jls/se26/html/jls-17.html
Supports
- A monitor permits one thread at a time to hold its lock
- Incorrect synchronization can produce counterintuitive shared-memory observations
- Happens-before includes program order and synchronizes-with ordering
- Conflicting accesses not ordered by happens-before form a data race
- Programs that acquire several locks need a deadlock-avoidance discipline
- https://doc.rust-lang.org/book/ch16-01-threads.html
Supports
- Threads are independent execution paths within a program and can run simultaneously
- Thread scheduling order is not guaranteed
- Threads introduce race-condition, deadlock, and reproducibility risks
- Joining waits for a spawned thread to complete
- https://doc.rust-lang.org/book/ch16-02-message-passing.html
Supports
- Channels transfer data between threads
- A blocking receive waits for a value while a nonblocking receive returns immediately
- Channel closure communicates that no more values will arrive
- Messages from concurrent producers can arrive in nondeterministic order
- https://doc.rust-lang.org/book/ch16-03-shared-state.html
Supports
- Shared-state concurrency allows multiple threads to access the same memory
- A mutex provides exclusive access to guarded data
- Lock acquisition can block until the mutex becomes available
- Scope-bound guards can release a lock automatically
- https://docs.python.org/3/library/asyncio-task.html
Supports
- Asyncio tasks schedule coroutines cooperatively
- An event loop runs one task at a time and runs other tasks when the current task awaits
- Task groups provide a structured way to wait for related tasks
- Cancellation, waiting, sleeping, and timeouts are explicit task operations
- https://docs.python.org/3/library/asyncio-queue.html
Supports
- An asyncio queue can have a maximum size
- Adding to a full bounded queue waits until space becomes available
- Queue task tracking can wait until queued work is processed
- https://docs.python.org/3/library/concurrent.futures.html
Supports
- Executors provide a high-level interface for asynchronous callable execution
- Thread and process pools use bounded sets of workers configured by the caller or implementation
- Waiting on dependent futures within a pool can deadlock
- https://go.dev/doc/articles/race_detector
Supports
- Go provides dynamic race detection through the race option
- Race reports include conflicting accesses and their creation stacks
- The detector finds races only on execution paths that run
- Running realistic workloads can increase dynamic coverage
- https://www.cs.utexas.edu/~EWD/transcriptions/EWD01xx/EWD123.html
Supports
- Dijkstra described cooperation between loosely connected sequential processes in 1965
- https://ora.ox.ac.uk/objects/uuid%3A833f1ea8-feba-4d81-b419-83e6f5f24e81
Supports
- Hoare published A Model for Communicating Sequential Processes in 1978
- https://erlang.org/course/history.html
Supports
- Erlang experiments from 1985 through 1986 established concurrency and error recovery as language requirements
- https://standards.ieee.org/ieee/1003.1c/1393/
Supports
- IEEE 1003.1c-1995 was the POSIX threads extension
- The standard was approved in 1995 and published in 1996
- https://jcp.org/en/jsr/detail?id=133
Supports
- JSR 133 revised the Java memory model and threading specification
- https://go.dev/blog/1year
Supports
- The Go project launched on 10 November 2009
- https://blog.rust-lang.org/2015/05/15/Rust-1.0/
Supports
- Rust 1.0 was announced on 15 May 2015 with a stability commitment
- https://blog.jetbrains.com/kotlin/2018/10/kotlin-1-3/
Supports
- Kotlin 1.3 shipped multiplatform coroutine libraries in 2018
- https://openjdk.org/jeps/444
Supports
- JDK 21 delivered virtual threads in 2023
- Virtual threads are lightweight threads implemented by the JDK
- JEP 444 advises against pooling virtual threads
