Concurrent Programming
Concurrent programming writes code that correctly executes multiple tasks whose operations overlap in time. It addresses thread management, locks, atomic operations, message passing, and the patterns that prevent data races and deadlocks in shared-memory and distributed systems.
itSoftware engineering | OpenSkills.info
Course pathWalk it in order
Look it upDip in anytime
Go furtherLeaves this page
Don't Panic
Don't Panic — Concurrent Programming
Concurrent programming is the art of letting several pieces of work make progress during the same stretch of time without allowing them to turn the program into a haunted house of timing accidents. The tasks might take turns on one core, or run together on several. That second arrangement is parallelism. It is related, but it is not the same creature wearing a faster hat.
Before concurrency, the comforting default was sequential code: one operation finishes, then the next begins. Once a scheduler can interleave tasks, many orders become valid. A test that passes once has therefore proved that one order was polite on one occasion. It has not made a treaty with the other orders.
The first thing to remember is ownership: who may change a mutable value? The nicest answer is often one task, or no task because the value is immutable. The next best answer may be a message passed through a queue or channel. When state really must be shared, use synchronization to protect the whole invariant, not one nearby-looking line. A counter and an account transfer both have a talent for becoming more than one operation when nobody is watching.
The second is ordering. A lock, channel operation, thread start, join, or documented atomic operation can establish happens-before: the visibility and ordering promise another task may rely on. The calendar does not establish it. Neither does a log line that happened to arrive first, which is unfortunate because logs look so confident.
The third is lifetime. Tasks need an owner, a cancellation path, an error path, and a cleanup path. Bounded pools and queues add backpressure, which means overload becomes an explicit decision instead of a slow conversion of memory into anxiety. A caller that stops waiting while its work continues has not solved the problem; it has merely moved it somewhere less conversational.
Read the introduction for the full map of processes, threads, tasks, coroutines, and synchronization. Use the slides when the relationships need a diagram. Keep the cheatsheet nearby when choosing a primitive, tracing a liveness failure, or reviewing queue and shutdown rules. The quiz is where the terms stop nodding politely and start asking whether they have been understood.
Where this skill leads
Relevant careers
See how this topic contributes to broader role-level skill maps.
Sources
- https://go.dev/ref/mem
Supports
- Data races as conflicting accesses unordered by happens-before
- Happens-before as the transitive ordering built from program sequencing and synchronization
- Synchronization effects of goroutine creation, channels, mutexes, once, and atomic operations
- Data-race-free execution and sequential consistency
- https://docs.oracle.com/javase/specs/jls/se26/html/jls-17.html
Supports
- Monitor locking and unlocking
- Wait sets, notification, interruption, and thread joins
- Synchronization order, synchronizes-with edges, and happens-before
- Data-race definition and allowed execution behavior
- https://docs.oracle.com/javase/tutorial/essential/concurrency/interfere.html
Supports
- Compound steps inside an increment or decrement
- Lost updates caused by interleaved read-modify-write operations
- Timing-dependent nature of thread-interference defects
- https://docs.oracle.com/javase/tutorial/essential/concurrency/memconsist.html
Supports
- Memory visibility between threads
- Happens-before effects of thread start and join
- https://docs.oracle.com/javase/tutorial/essential/concurrency/liveness.html
Supports
- Liveness as timely execution
- Deadlock, starvation, and livelock as liveness problems
- https://docs.oracle.com/javase/tutorial/essential/concurrency/deadlock.html
Supports
- Deadlock as threads blocked forever while waiting for one another
- Circular lock dependency example
- https://doc.rust-lang.org/book/ch16-02-message-passing.html
Supports
- Channels for communication between threads
- Multiple producers and transferred values
- Ownership constraints after sending a value
- https://doc.rust-lang.org/book/ch16-03-shared-state.html
Supports
- Shared-memory concurrency and multiple ownership
- Mutex-protected access
- Atomic reference counting for shared ownership across threads
- https://docs.python.org/3/library/concurrent.futures.html
Supports
- Executors as a high-level interface for asynchronous callable execution
- Threads, processes, and interpreters behind a shared executor interface
- Futures as handles for submitted execution
- Executor shutdown and cancellation behavior
- Deadlock when pool tasks wait cyclically or exhaust available workers
- https://docs.python.org/3/library/asyncio-task.html
Supports
- Coroutines, tasks, task groups, cancellation, and timeouts
- Task groups as structured concurrency scopes
- Child failure propagation, sibling cancellation, and cleanup before scope exit
- https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/V1_chap04.html
Supports
- Mutex acquire and release memory synchronization
- Condition wait release and reacquisition behavior
- Semaphore count and blocking behavior
- Data races and memory-order concepts in POSIX.1-2024
- https://pubs.opengroup.org/onlinepubs/9799919799/functions/pthread_cond_wait.html
Supports
- Atomic release and reacquisition of the associated mutex during a condition wait
- Re-evaluation of the predicate after return
- https://www.cs.cmu.edu/~crary/819-f09/Hoare78.pdf
Supports
- The 1978 communicating sequential processes paper and its communication model
- https://erlang.org/download/armstrong_thesis_2003.pdf
Supports
- Erlang work beginning in 1986 and its early concurrent-process experiments
- https://cr.openjdk.org/~vlivanov/talks/2015_Java_20_years_Minsk.pdf
Supports
- Java's first release in 1996 and its release history
- https://jcp.org/en/jsr/detail?id=166
Supports
- Java concurrency utilities including executors, futures, locks, and atomic variables
- https://go.dev/blog/toward-go2
Supports
- Go's November 2009 open-source release and March 2012 Go 1 release
- https://blog.rust-lang.org/2015/05/15/Rust-1.0/
Supports
- Rust 1.0 release and its stability commitment
- https://blog.jetbrains.com/kotlin/2018/10/kotlin-1-3/
Supports
- Kotlin 1.3 and stable coroutines
- https://openjdk.org/jeps/428
Supports
- Structured Concurrency as a JDK 19 incubating API
- https://engineering.clever.com/2018/03/16/postmortem-last-weeks-outages/
Supports
- Continued work after client timeouts consuming database concurrency capacity
- Retries amplifying contention during an outage
