serversim
LearnSimulatorTemplatesPricing
…
…
Open menu
Learn↗Simulator↗Templates↗Pricing↗
My DocumentsDocs
Contents/Chapter 88 / 16

Threads — born because processes were heavy

What goes wrong if you start 200 whole programs to take 200 requests at once? Instead of renting a separate office per customer, share one office and simply add more people who can sit at the counter.

See this first in FoundationsCan a computer do something else while it waits?→

Say a web server must handle 200 requests at once. A process per request means 200 memory spaces and OS-mediated messaging for every shared piece of data — far too expensive. Hence threads: share the memory, multiply only the flows of execution.

① What a thread keeps to itself

Threads in one process share the heap, the code and open files, but each keeps its own stack — necessarily, since each is inside a different function with its own locals and return addresses. Creating a thread is roughly "one more stack plus one more context", far cheaper than a process.

② The three states

To the OS a thread is Running (owns the CPU), Ready (could run, waiting its turn), or Waiting (asleep on IO). Chapter 7's waiting is Waiting, and chapter 6's context switching was really moving between these states.

③ A sleeping thread uses zero CPU

This is the most misunderstood point in the series. Waiting threads are not scheduling candidates at all, which is why "the server accepts nothing yet CPU is 10%" is a real situation. The blockage is not the CPU; every thread is simply asleep.

④ The price of sharing — races

Sharing a heap is convenient and dangerous. If two threads modify the same variable, results depend on exactly when the switch happened, so they can differ run to run. That is a race condition, and it is why locks exist.

⑤ How cheap a thread is — and where it stops being cheap

Creating a thread is far cheaper than creating a process, but it is not free. Each thread needs its own stack (conventionally a few hundred KB up to 1 MB), and as thread counts grow the kernel run queue lengthens and scheduling itself slows down. Thousands of threads are practical; tens of thousands are not. That ceiling is the heart of the C10K story later on.

⑥ Locks buy correctness and sell parallelism

Shared memory needs locks to be safe. A lock buys correctness by selling parallelism: only one thread may be inside the guarded section, so the longer that section runs, the longer everyone else simply queues. Hold locks briefly — and waiting on IO while holding one is almost always the beginning of an incident.

Speed

Try it in the simulator

  1. 1.Open the 'HikariCP pool exhaustion' preset at its default (HikariCP pool 5, Tomcat threads.max at its default 200) — the KPI panel's drop breakdown shows 1,424 pool-exhausted: threads that hit the 1s acquire timeout.
  2. 2.200 threads chase 5 connections. This is the thread waiting state from this chapter, made concrete — the KPI panel's Success sits at just 2.4%.
Try it in the simulator →

Terms in this chapter

thread
A flow of execution inside a process. Shares the heap, keeps its own stack.
Running / Ready / Waiting
On the CPU / waiting a turn / asleep on IO.
race condition
Results changing run to run because threads touched the same data concurrently.
lock
A device letting only one thread into a section at a time — prevents races, creates waiting.
run queue
The line of threads ready to be given a CPU. Longer queues cost scheduling time.
lock contention
Threads queueing for the same lock; parallelism disappears.

Why it evolved this way

Threads exist precisely because of process costs: cheap creation, easy sharing, light switches. The price is isolation — one thread can take the whole process down.

Blocking = leaving the CPU (Waiting), not using it.

The remaining problem

Switching got cheaper — but does adding threads always help? →

← Previous

Chapter 7. Discovering the wait — IO idles the CPU

Next →

Chapter 9. Concurrency ≠ parallelism