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
// 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| State | When |
|---|---|
| NEW | After new Thread(), before start() |
| RUNNABLE | After start() — running or waiting for CPU |
| BLOCKED | Waiting for a monitor lock (synchronized) |
| WAITING | wait(), join() — waiting indefinitely |
| TIMED_WAITING | sleep(ms), wait(timeout) |
| TERMINATED | run() completed |
synchronized — The Lock
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
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-writewait/notify — Thread Communication
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
ExecutorService pool = Executors.newFixedThreadPool(4);
pool.submit(() -> { /* task */ });
// Instead of new Thread().start() for every taskFinal 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. Alwayswhile, notif. PrefernotifyAll.
Thread pools reuse threads — don'tnew Thread()for every task.