A thread is the smallest unit of execution that a CPU can schedule and run, a single sequence of instructions moving through your program. A program with multiple threads can do several things seemingly at once: download a file on one thread while keeping the interface responsive on another. Threads live inside a process and share its memory, which makes them fast to coordinate but also the source of some of the trickiest bugs in software. In 2026, understanding threads is still essential even though many languages now hide them behind friendlier tools.
The core idea
When you run a program, the operating system creates a process for it with its own block of memory. Inside that process, at least one thread runs the actual instructions. You can spawn more threads, and the operating system rapidly switches between them, or runs them truly in parallel on multiple CPU cores.
Concurrency means making progress on more than one task by interleaving them. Parallelism means literally running them at the same instant on different cores. Threads can do both.
Threads vs processes
| Aspect |
Thread |
Process |
| Memory |
Shares the process memory |
Has its own isolated memory |
| Creation cost |
Cheap and fast |
Heavier |
| Communication |
Direct, via shared memory |
Needs explicit messaging |
| Failure blast radius |
Can corrupt sibling threads |
Isolated from other processes |
The shared memory is the double-edged sword. Threads talk to each other almost for free because they see the same data. But if two threads write the same data at the same time, the result is unpredictable.
Why threads cause bugs
When two threads touch the same variable without coordination, you get a race condition: the outcome depends on the unpredictable timing of who runs first.
// Two threads incrementing the same counter can lose updates
counter = 0
def add():
for _ in range(100000):
global counter
counter += 1 // read, add, write is not atomic
That innocent counter += 1 is actually three steps, and another thread can sneak in between them. The fix is synchronization, the most common form being a lock that lets only one thread into a critical section at a time. Languages like Go vs Rust in 2026 take notably different approaches to making this safe.
Tools for safe concurrency
- Locks (mutexes). Guard shared data so only one thread touches it at once.
- Thread pools. Reuse a fixed set of worker threads instead of spawning thousands.
- Queues. Hand work between threads safely without sharing raw state.
- Async / await. In languages like Python and JavaScript, an event loop handles many waiting tasks on one thread, often simpler than raw threads.
- Immutable data. If data never changes, threads can read it freely with no locks.
How to choose your approach
- I/O-bound work (network, disk, waiting) often fits async or a small thread pool well, because the threads spend most of their time idle.
- CPU-bound work (heavy computation) benefits from true parallelism across cores; in some languages that means processes rather than threads.
- A handful of background tasks rarely needs hand-managed threads at all; a higher-level scheduler is safer.
Common mistakes
- Sharing mutable state without a lock. This is the root of most threading bugs.
- Deadlock. Two threads each wait for a lock the other holds, and both freeze forever. Always acquire locks in a consistent order.
- Spawning unbounded threads. Creating a thread per request will exhaust memory under load; use a pool.
- Assuming order. Without synchronization, you cannot predict which thread runs when.
What to skip
- Raw threads for everything. If async or a thread pool fits, use it; the abstraction prevents whole categories of bugs.
- Premature concurrency. A simple single-threaded program is easier to reason about. Add threads when you have a measured need.
- Clever lock-free tricks before you are fluent in the basics. They are powerful and easy to get subtly wrong.
FAQ
What is the difference between a thread and a process?
A process has its own isolated memory; a thread runs inside a process and shares that memory with sibling threads. Threads are cheaper to create and communicate, but riskier to share data between.
What is a race condition?
A bug where the result depends on the unpredictable timing of multiple threads accessing shared data. The classic example is two threads incrementing the same counter and losing updates.
Are threads the same as async?
No. Async uses an event loop to juggle many waiting tasks, often on a single thread. Threads can run truly in parallel. Async suits I/O-bound work; threads or processes suit CPU-bound work.
Why does my multithreaded code give different results each run?
Almost always unprotected shared state. Threads interleave differently each time, so without locks or other synchronization the outcome varies.
Where to go next
See what concurrency is in 2026, what an operating system is in 2026, and what a variable is in 2026.