Theory
The desk freezes at 5 pm
New BookBridge feature: at closing time, scan all issued books and print reminders for anything near its due date. 6000 records, about 40 seconds.
Problem: while that scan runs, the return desk is frozen. The program is busy; the librarian clicks, nothing responds, a queue forms.
The scan does not need the desk; they just live in the same program, taking turns on one path of execution. What we want is a second path. Java calls it a thread.
Theory
Two assistants, one library
So far every program you have written is a library with one assistant doing everything in sequence: serve a member, then check reminders, then update the register.
A thread hires a second assistant inside the same library: same shelves, same records (the same objects and memory), working simultaneously. One serves the desk, the other quietly walks the shelves making the reminder list. The building does not wait for the walk to finish.
Theory
Thread and its life, formally
A thread is an independent path of execution within a program. Every Java program already has one: the JVM runs main on the main thread; you create more.
The thread model is the life cycle every thread walks:
- New: created, start() not yet called
- Runnable: ready, waiting for the scheduler's turn
- Running: currently executing on the CPU
- Blocked/Waiting: paused for a resource, sleep or another thread
- Dead: run() finished; a dead thread cannot be restarted
Practical
The reminder gets its own assistant
class Reminder implements Runnable { // sign the contract
public void run() { // the thread's task lives here
for (int i = 1; i <= 3; i++) {
System.out.println("Reminder check " + i);
}
}
}
public class BookBridge {
public static void main(String[] args) {
Thread t = new Thread(new Reminder());
t.setPriority(Thread.MAX_PRIORITY); // 10: a hint, not an order
t.start(); // birth of the second path
System.out.println("Desk keeps serving");
}
}
Theory
Two ways in, one clear winner
Java offers 2 creation routes:
- extends Thread: your class IS a thread; override run(), call start()
- implements Runnable: your class HAS a task; hand it to
new Thread(task)
Prefer Runnable, and say why in the exam: Java classes get one extends slot (single inheritance). Reminder may need to extend some other class someday; implementing Runnable keeps that slot free. It also separates the task (what to do) from the machinery (the Thread that runs it), and it is last unit's interface pattern working for a living.
Quiz
A student writes t.run() instead of t.start(). The program works, so what actually changed?
- Nothing; run() and start() are synonyms
- No new thread was created: run() executed like an ordinary method call on the current thread
- The thread ran, but at minimum priority
- Compile error: run() cannot be called directly
Show the answer
No new thread was created: run() executed like an ordinary method call on the current thread
start() is the magic step: it asks the JVM to create a genuinely new path of execution, which then calls run() on that new thread. Call run() yourself and it is just a normal method call: the reminder loop runs on the MAIN thread, sequentially, desk frozen again, exactly the problem we came to solve. The output can look identical, which is why this bug survives testing. Options C and D invent behaviour: priority is untouched and the call is perfectly legal, just wrong.
Think first
Who prints first?
In the listing, the reminder thread has MAX_PRIORITY. Before tapping: is "Reminder check 1" guaranteed to appear before "Desk keeps serving"?
Show the answer
No. Priority (MIN_PRIORITY 1, NORM_PRIORITY 5, MAX_PRIORITY 10) is a suggestion to the thread scheduler, not a command; the scheduler and the operating system still decide who runs when. main may well print its line before the new thread gets its first turn, and 2 runs of the same program can interleave differently. Exam sentence: thread priority influences scheduling but guarantees nothing. Never build program correctness on priorities.
Watch out
Three thread traps
run() instead of start(): no new thread, silently sequential: the quiz above, and the #1 practical bug.
Restarting a dead thread: once run() completes, calling start() again throws IllegalThreadStateException; make a new Thread object instead.
Trusting output order: any answer that claims a fixed interleaving of 2 running threads is wrong; write "order is unpredictable" and you are the one being precise.
Theory
Threads you have already met
Every Android app from BCA305-02 runs its screens on a main thread (freeze it and the OS shows "app not responding", the same 5 pm desk problem). StringBuffer's synchronized methods from last unit exist exactly because 2 threads may edit one buffer. And the Runnable in today's listing is the interface contract from Unit 2, signed and earning its keep. Next lesson zooms out: organising BookBridge's growing pile of classes into packages.
Summary
Key takeaways
- A thread is an independent execution path inside one program; main runs on the main thread.
- Life cycle: new, runnable, running, blocked/waiting, dead; dead threads never restart.
- Create via extends Thread or (preferred) implements Runnable + new Thread(task): keeps the extends slot free.
- start() births the new thread which calls run(); calling run() directly is just a method call on the current thread.
- Priorities: 1 (MIN), 5 (NORM), 10 (MAX), set with setPriority(): hints to the scheduler, never guarantees.
- Output order between running threads is unpredictable; say so in exams.
- Memory hook: start() hires the assistant, run() is just you doing the work yourself.