Back to the map

Module 03 · Processes and threads · Lesson 2 of 7

Threads vs processes

Threads share their process's memory and files while each keeps its own stack and registers. What that sharing buys (cheap communication, low overhead) and costs (races, one crash kills all), kernel versus user-level threads.

CoreMust-knowJunior 12 min Updated Nov 2026

Why it matters

"Should this be a thread or a process?" sits under every concurrency decision: a web server's worker model, a browser's architecture, why Python uses multiprocessing for CPU work, why Go can run a million goroutines. The answer depends on what you want shared, what you want isolated, and how much each option costs, and interviewers use the question to test whether you understand both.

The idea

A thread is an independent stream of execution inside a process. All threads of a process share its address space, heap, open files and credentials; each thread has its own stack, registers and program counter. So threads can communicate by simply reading and writing the same memory, which is fast and also the source of every race condition.

process AHeap, globals, open filesThread 1stack, regsThread 2stack, regsshare memory directlyprocess BHeap, globals, open filesThread 1stack, regsThread 2stack, regstalks to A only via IPC
Two processes with two threads each. Threads in a process share the heap and file descriptors; each has a private stack. Between processes, nothing is shared without the kernel's help.
Threads in one processSeparate processes
MemoryShared heap; private stacksFully private
CommunicationRead and write shared variables, guarded by locksPipes, sockets, shared memory segments, message queues
Creation costTens of microseconds; a stack (often 1 to 8 MB reserved)Higher: new address space and kernel structures
Switching costCheaper: same address space, caches and TLB stay warmDearer: address space switch, TLB flush on many CPUs
FailureA crash or memory corruption takes down every threadIsolated: one process dies, the rest continue
Security boundaryNone between threadsYes; the kernel enforces it
Typical useRequest handling within a server, parallel computation on shared dataWorkers that must not affect each other, sandboxes, separate services

Concurrency and parallelism

Concurrency is about structure: several tasks in progress at once, interleaved. Parallelism is about execution: several tasks literally running at the same instant on different cores. Threads give you both when the runtime allows it. CPython's global interpreter lock is the well-known exception: Python threads interleave but only one runs Python bytecode at a time, so CPU-bound Python code uses processes (multiprocessing) for parallelism, while I/O-bound code can still benefit from threads because the lock is released while waiting. (Recent CPython versions offer an optional build without the lock.)

Kernel threads and user-level threads

  1. 1

    Kernel threads (one-to-one)

    Each thread is known to and scheduled by the kernel. True parallelism, blocking calls block only that thread, and creation and switching go through the kernel. Java's platform threads and pthreads on Linux work this way.
  2. 2

    User-level threads (many-to-one)

    A library schedules many lightweight threads on one kernel thread. Very cheap to create and switch, but a blocking system call stalls all of them and they cannot use more than one core. Early green-thread systems worked this way.
  3. 3

    Many-to-many (M:N)

    A runtime multiplexes many lightweight threads over a pool of kernel threads, parking those that block on I/O and running others. Go's goroutines, Java's virtual threads and Erlang processes take this approach, which is how a single server can hold hundreds of thousands of concurrent tasks with small, growable stacks.

Choosing

Use threads, or a runtime's lightweight threads, for concurrent work on shared data inside one service: handling requests, parallel loops, background tasks. Use processes when failures must not spread, when untrusted code must be sandboxed, when you need parallelism in a runtime with a global lock, or when components are deployed and scaled independently. Many servers combine them: a few processes (often one per core or per container) each running many threads or an event loop.

Trade-offs

Threads trade isolation for speed of communication and lower overhead, and hand you the hardest class of bugs (races, deadlocks, memory corruption shared by all). Processes trade speed for safety. Lightweight thread runtimes reduce the cost of having many threads, but not the cost of sharing memory unsafely.

In an interview

Tie the choice to failure and sharing: "Image processing runs in separate worker processes because a malformed file can crash the decoder and we do not want that to take down request handling. Request handling itself uses a thread pool sized to the cores, sharing an in-memory cache." For high concurrency: "With mostly idle connections we would use goroutines or virtual threads rather than a platform thread per connection."

Check yourself

A Python service does CPU-heavy image resizing. Moving the work from 1 thread to 8 threads on an 8-core machine barely improves throughput. Why, and what helps?

Threads vs processes · Backplane