Processes vs Threads Explained: How Programs Run Concurrently
Every running program on your computer is more than a file on disk. Once you launch it, the operating system turns that program into a living unit of work. That unit is a process. Inside many processes, smaller units of work called threads actually execute instructions on the CPU.
If you write backend servers, mobile apps, browsers, games, or any software that does more than one thing at a time, you will meet processes and threads constantly. Understanding the difference explains why some bugs appear only under load, why one crash can take down an entire app, why Python has a GIL discussion, and why Node.js, Java, Go, and browsers choose different concurrency models.
This guide explains what processes and threads are, how the operating system manages them, how they share or isolate memory, and how developers use them in real systems.
What Developers Mean by Process and Thread
A process is a running instance of a program. When you open a browser, start a Python script, or launch a database server, the operating system creates a process. That process owns its own virtual address space, open files and sockets, security credentials, at least one thread of execution, and kernel bookkeeping such as a process ID (PID).
A thread is the unit the CPU actually schedules. A process starts with one main thread. Additional threads can be created inside the same process so multiple sequences of instructions run at once, or at least appear to run at once.
Think of a process as a workshop with its own tools, floor space, and locked door. Threads are workers inside that workshop. They share the same tools and floor. Workers in a different workshop cannot walk in and grab those tools without going through a formal, slower doorway.
Simple Explanation
Computers look like they run dozens of apps at once. In reality, a CPU core executes one thread at a time. The operating system rapidly switches between threads. That switching is so fast that you perceive simultaneous activity. This is concurrency: many tasks in progress, interleaved over time.
Parallelism is different. Parallelism means two or more threads truly run at the same instant on different CPU cores. Concurrency is about structure. Parallelism is about hardware doing work at the same moment.
A single-core machine can be highly concurrent. It cannot be meaningfully parallel for CPU-bound work. A multi-core machine can be both. A web server handles thousands of connections concurrently even if only a few requests use the CPU at the same instant. A video encoder wants parallelism so multiple cores compress frames together. A UI thread must stay responsive while background threads load data.
How It Works Internally
From executable file to running process
When you start a program, the operating system typically allocates a process control block in the kernel, creates a virtual address space, maps the executable and shared libraries, allocates a stack for the main thread and a heap for dynamic memory, sets the instruction pointer to the program entry point, and places the new thread on a scheduler run queue.
On Linux, creating a process usually involves fork() or clone(), then exec() to load a new program image. On Windows, CreateProcess builds the address space and starts the first thread.
Memory isolation vs shared memory
Each process has its own virtual memory. The same numeric address in process A is not the same physical page as in process B. The Memory Management Unit and page tables enforce this isolation. If a process writes to an invalid address, it fails and other processes keep running.
Threads in the same process share the heap, global and static variables, program code, and typically open file descriptors. Each thread still has its own stack, registers, thread-local storage, and scheduling state. Shared heap memory is why threads are fast to communicate and dangerous to coordinate.
The scheduler
The kernel scheduler decides which thread runs on which CPU core. A thread runs until its time slice ends, it blocks on I/O or a lock, or it yields or exits. Then the kernel performs a context switch: save one thread's registers and load the next thread's registers. Thread switches stay inside one address space and are cheaper than process switches.
Threads block when they wait for disk, network, timers, or locks. While blocked, they do not consume a CPU core. A server can have far more threads than cores if most threads wait on I/O. CPU-bound work does not benefit from thousands of extra threads.
User-level threads and kernel threads
Most languages map language threads to kernel threads (1:1). Some runtimes use user-level scheduling on a smaller pool of kernel threads (M:N). Go goroutines, Java virtual threads, and many async runtimes work this way. Isolation and crash rules still follow the process boundary.
User -> Browser process -> Network -> Server process (event loop + workers) -> Database process
Browsers isolate tabs into processes for security. Databases often use many threads inside one process for shared caches.
Processes vs Threads Compared
Process: isolated memory, crash contained, higher creation cost, IPC for communication, strong security boundary. Thread: shared memory, crash can kill the process, cheaper creation, direct shared-state communication, weak isolation inside the process. Both can use multiple CPU cores.
Real-World Examples
Modern browsers use a multi-process architecture so a crashed or compromised tab does not take down every other tab. Inside a renderer, multiple threads parse HTML, run JavaScript, and composite graphics.
A standard Node.js process uses one main JavaScript thread plus a small libuv thread pool. Concurrency comes from the event loop. CPU-heavy work needs worker threads or extra processes.
CPython has a Global Interpreter Lock in common builds, so threads help I/O but CPU-bound Python work usually scales with processes. Classic Java servers use thread pools. Go schedules many goroutines onto fewer OS threads. PostgreSQL often uses a process per connection with shared memory.
Code Examples
import os
from multiprocessing import Process
def worker(name):
print(name, os.getpid())
if __name__ == '__main__':
p1 = Process(target=worker, args=('A',))
p2 = Process(target=worker, args=('B',))
p1.start(); p2.start(); p1.join(); p2.join()
Process starts a new interpreter with its own memory.
import threading
counter = 0
lock = threading.Lock()
def bump():
global counter
for _ in range(100000):
with lock:
counter += 1
t1 = threading.Thread(target=bump)
t2 = threading.Thread(target=bump)
t1.start(); t2.start(); t1.join(); t2.join()
print(counter)
Both threads touch the same counter. Remove the lock and you can get a race condition. On Linux use ps aux for processes and ps -L -p PID for threads.
Common Misconceptions
Threads are not always faster. More threads do not always mean more speed. Async is not the same as multithreading. Every process has at least one thread. Forcibly killing one thread is not as safe as exiting a process, because shared locks and heaps can be left inconsistent.
Best Practices and Key Takeaways
- Use processes for hard isolation, crash containment, and separate privileges.
- Use threads or lightweight tasks when work must share memory cheaply.
- Prefer message passing over ad-hoc shared mutable state.
- Protect shared data with locks or atomics. Keep critical sections short.
- Do not block UI threads or event-loop threads on slow work.
- Size thread pools from the workload. Measure contention.
- Remember: processes isolate; threads share.
FAQ
What is the difference between a process and a thread?
A process is a running program with its own memory. A thread is an execution path inside a process. Threads of the same process share memory.
Can one process have multiple threads?
Yes. Browsers, JVM servers, and game engines do this routinely.
Do threads run in parallel?
They can on multiple cores. On one core they only interleave. Parallelism needs hardware; concurrency does not.
Why do browsers use multiple processes?
Security and reliability. Process isolation stops one page from reading another site's memory or freezing the whole browser.
Is multithreading better than multiprocessing?
Neither is always better. Many production systems use several processes, each with a thread pool.
What is a race condition?
A result that depends on unpredictable timing between threads that share data without synchronization.
What is a deadlock?
A cycle of waits, such as two threads each holding a lock the other needs.
How do async and threads compare?
Async overlaps waits on one thread. Threads schedule multiple stacks and can use extra cores.