Quick Answer

Processes have separate memory; threads within a process share it. Sharing makes threads cheap to create and fast to communicate, and it is also why threads can corrupt shared data and processes cannot.

The difference that explains all the others

A process is a running program with its own memory space. Two processes cannot read each other's variables — the operating system prevents it. That isolation is why a crashing browser tab does not take down the whole browser.

A thread is a unit of execution inside a process. Threads in the same process share the same memory. They have their own stack and program counter, but the heap is common.

Every consequence follows from that:

  • Creating a thread is much cheaper, because there is no new memory space to set up.
  • Threads communicate by reading the same variables; processes need explicit inter-process communication.
  • One thread crashing can bring down the whole process; one process crashing leaves others untouched.
  • Threads can corrupt shared data. Processes cannot, because they have nothing shared to corrupt.

The race condition, demonstrated

Four threads each increment a shared counter 50,000 times. The expected total is 200,000. Running it in Java:

static int counter = 0;

// four threads, each doing:
for (int k = 0; k < 50000; k++) counter++;
expected 200000, unsynchronised got: 76235

Over 120,000 increments vanished. The reason is that counter++ is not one operation — it is read, add one, write back. Two threads can read the same value, both add one, and both write back the same result. One increment is lost, and it happens constantly.

That number is also different on every run, which is what makes these bugs so unpleasant: the program is correct most of the time and wrong unpredictably.

With an atomic counter, which makes the read-modify-write indivisible:

with AtomicInteger got:      200000

Exactly right, every time. That is what synchronisation buys.

When to use which

Threads suit work inside one application that needs shared data: a web server handling many requests against a shared cache, a UI keeping its interface responsive while work happens in the background, or several downloads writing into one structure.

Processes suit isolation and true parallelism: running untrusted code, keeping one crash from taking down everything, and — in Python specifically — using multiple CPU cores.

That Python caveat is worth knowing because it surprises people. CPython's global interpreter lock means only one thread executes Python bytecode at a time, so threads do not give you parallel CPU work. They still help for input/output waiting — network calls, file reads — because the lock is released while waiting. For CPU-bound work use multiprocessing, which uses separate processes and sidesteps the lock.

The related terms you will be asked about

  • Context switch — the operating system saving one task's state and loading another's. Switching between threads is cheaper than between processes, because the memory mappings do not change.
  • Concurrency vs parallelism — concurrency is dealing with several things at once, which is possible on a single core by interleaving. Parallelism is doing them at the same instant, which needs multiple cores.
  • Critical section — the part of the code that touches shared data. It must be entered by only one thread at a time.
  • Mutex — a lock ensuring exactly that.
  • Deadlock — two threads each holding a lock the other needs, so neither proceeds. See deadlock explained.

How this is actually asked

Rarely as a definition. More often as: "Why did this counter give the wrong number?", "How would you make this thread-safe?", or "Why is your Python program not faster with four threads?"

Good answers name the shared mutable state, identify the critical section, and propose the smallest correct fix — an atomic type or a lock around just the shared access. Locking too much is a real cost: a lock around the entire loop serialises the threads and removes the point of using them.

The underlying principle worth stating: shared mutable state is the source of concurrency bugs. Remove the sharing, or remove the mutation, and most of the problem disappears. That is why immutable data and message passing are popular in concurrent systems.

Frequently Asked Questions

What is the main difference between a process and a thread? Memory. Processes have separate memory spaces and are isolated from each other; threads within a process share memory, which makes them cheaper and faster to coordinate but able to corrupt shared data.
Why is my multithreaded Python program not faster? CPython's global interpreter lock allows only one thread to run Python bytecode at a time, so threads do not parallelise CPU-bound work. Use multiprocessing for that; threads still help for input/output waiting.
What is a race condition? When the result depends on the unpredictable timing of concurrent operations. The classic case is two threads incrementing a shared counter, where a read-modify-write sequence interleaves and updates are lost.
How do I make code thread-safe? Protect shared mutable state with a lock or use atomic types. Keep the protected region as small as correctness allows, since locking too broadly serialises the work and removes the benefit of threading.
Is concurrency the same as parallelism? No. Concurrency is structuring a program to handle several tasks that overlap in time, which works on one core. Parallelism is genuinely executing them simultaneously, which requires multiple cores.