Skip to content

Metadata Card

  • Prerequisites: Ch5 (Methods & Stack), Ch6 (Arrays)
  • Estimated time: 90 min
  • Core difficulty:
  • Reading mode: High pressure mode (read when alert)
  • Completion marker: Can understand and create threads, use synchronized for shared data protection, understand thread state transitions, basic thread pool usage

The Breakthrough · Tracing the Origins

Your library system works perfectly for one user. Then 100 users log in simultaneously. Your 8-core CPU only uses 1 thread — the other 7 cores are idle. Worse: two threads read the same "last book" in stock, and both successfully borrow it — even though there's only one physical copy.

Concurrency is your first "real hard problem." The bugs here are more numerous than all previous bugs combined.

Creating Threads

java
// Method 1: Extend Thread
class DownloadThread extends Thread {
 public void run() { /* code runs in new thread */ }
}
new DownloadThread().start(); // NOT run()!

// Method 2: Implement Runnable (preferred)
Thread t = new Thread(() -> {
 System.out.println("Running in: " + Thread.currentThread().getName());
});
t.start();

Thread States

NEW → RUNNABLE → BLOCKED / WAITING / TIMED_WAITING → TERMINATED
StateWhen
NEWAfter new Thread(), before start()
RUNNABLEAfter start() — running or waiting for CPU
BLOCKEDWaiting for a monitor lock (synchronized)
WAITINGwait(), join() — waiting indefinitely
TIMED_WAITINGsleep(ms), wait(timeout)
TERMINATEDrun() completed

synchronized — The Lock

java
class SafeCounter {
 private int count = 0;

 public synchronized void increment() { // One thread at a time
 count++;
 }

 public synchronized int getCount() { return count; }
}

count++ is NOT atomic — it's "read → modify → write." Without synchronization, two threads can both read the same value and write back the same result, losing one increment.

volatile — Lightweight Visibility

java
private volatile boolean running = true;
// Writes to `running` are immediately visible to other threads
// But volatile doesn't guarantee atomicity — use synchronized for read-modify-write

wait/notify — Thread Communication

java
synchronized (sharedQueue) {
 while (queue.isFull()) {
 sharedQueue.wait(); // Release lock, wait
 }
 queue.add(item);
 sharedQueue.notifyAll(); // Wake up waiting threads
}

Rules: Always call wait/notify inside synchronized. Always use while (not if) for condition checking. Prefer notifyAll() over notify().

Thread Pools

java
ExecutorService pool = Executors.newFixedThreadPool(4);
pool.submit(() -> { /* task */ });
// Instead of new Thread().start() for every task

Final Challenge: Implement a bounded blocking queue with put() and take(). Use wait()/notifyAll() internally. Test with producer-consumer pattern.

Traveler's Notes

Thread = person. Runnable = the task. Separate them.
start()run(). Start creates a new thread; run executes in current thread.
count++ is three steps — read, modify, write. Protect it with synchronized.
volatile for visibility, synchronized for atomicity + visibility.
wait/notify = red/green light. Always while, not if. Prefer notifyAll.
Thread pools reuse threads — don't new Thread() for every task.

Built with VitePress | Software Systems Atlas