11.1 Creating Threads: Thread vs Runnable
| Aspect | extends Thread | implements Runnable |
|---|---|---|
| Inheritance slot | Consumed (no other parent possible) | Free — can extend another class |
| Design | Task and thread fused | Task separated from worker (better) |
| Sharing one task object | Awkward | Natural: many threads, one Runnable |
| Lambda-friendly | No | Yes — Runnable is functional |
Thread t = new Thread(() -> System.out.println("run by " + Thread.currentThread().getName()));
t.start(); // NEW thread executes run()
t.run(); // TRAP: ordinary method call on the CURRENT thread!
start() vs run() is the single most-asked question: start() allocates a new call stack and the JVM invokes run() on it; calling run() directly is just a normal method call. Calling start() twice throws IllegalThreadStateException.
11.2 Thread Lifecycle — Six States (Thread.State)
| State | Meaning | Entered by |
|---|---|---|
| NEW | Created, not started | new Thread(r) |
| RUNNABLE | Running or ready, awaiting CPU | start() |
| BLOCKED | Waiting to acquire a monitor lock | Contended synchronized |
| WAITING | Waiting indefinitely | wait(), join() |
| TIMED_WAITING | Waiting with a timeout | sleep(ms), wait(ms), join(ms) |
| TERMINATED | run() finished or threw | — |
sleep vs wait: sleep is static on Thread, keeps all locks, needs no monitor; wait is an Object method, releases the monitor, and must be called inside synchronized (else IllegalMonitorStateException).
11.3 Race Conditions & synchronized
count++ is three bytecodes (read, add, write). Two threads interleaving those steps lose updates — with two threads doing 100,000 increments each, the total prints less than 200,000 unpredictably. Fixes:
synchronizedmethod — locksthis(or the Class object if static).synchronized (lockObj) { ... }block — smaller critical section, custom lock.AtomicInteger.incrementAndGet()— lock-free CAS hardware instruction.volatileguarantees visibility of writes across threads but not atomicity ofcount++— a subtle distinction advanced papers love.
Every object owns one intrinsic lock (monitor); a thread may re-acquire a lock it already holds (reentrancy).
11.4 wait / notify — Producer-Consumer
Coordination pattern (guarded block): consumers wait() while the buffer is empty; producers add an item then notify()/notifyAll(). Always wait in a while loop, never an if — threads can wake spuriously, and the condition must be rechecked after reacquiring the lock. Prefer notifyAll() when multiple waiters have different conditions. (Full runnable version in the code snippet.)
11.5 Deadlock — The Classic Two-Lock Story
Thread-1 holds lock A and wants B; Thread-2 holds B and wants A — both wait forever:
// T1: synchronized(A){ synchronized(B){...} }
// T2: synchronized(B){ synchronized(A){...} } // opposite order => deadlock
Coffman conditions (all four required): mutual exclusion, hold-and-wait, no preemption, circular wait. Prevention: impose a global lock-acquisition order (both threads take A then B), use tryLock with timeout, or shrink to a single lock.
11.6 ExecutorService — Thread Pools (Modern Practice)
Creating raw threads per task is expensive; a pool reuses workers:
ExecutorService pool = Executors.newFixedThreadPool(4);
Future<Integer> f = pool.submit(() -> 6 * 7); // Callable returns a value
System.out.println(f.get()); // 42 (blocks until done)
pool.shutdown(); // orderly stop — always!
Know: newFixedThreadPool, newCachedThreadPool, newSingleThreadExecutor; Runnable vs Callable (void vs returns value + can throw checked); Future.get() blocks. Also join() (wait for a thread to die), daemon threads (JVM exits when only daemons remain), and thread priorities (1–10, only a hint to the scheduler).
🎯 Exam Focus
- Compare creating threads by extending Thread vs implementing Runnable. Why is Runnable preferred?
- Draw/describe the six-state thread lifecycle with the methods causing each transition.
- Differentiate start() vs run(), sleep() vs wait(), notify() vs notifyAll().
- What is a race condition? Write a program showing a lost-update on a shared counter and fix it with synchronized.
- Write the producer-consumer program using wait()/notifyAll(), and explain why wait() sits inside a while loop.
- What is deadlock? State the four Coffman conditions and two prevention strategies, with a two-lock code sketch.