🧵 Thread Fundamentals: The Kitchen Story
Imagine a busy restaurant kitchen. There’s one head chef (the computer’s CPU), but many orders coming in. How does the kitchen handle all those orders at once? By having multiple cooks working together!
That’s exactly what multithreading does for your Java programs.
🎯 What is Multithreading?
Think of your computer as that restaurant. Without multithreading, the head chef does one dish at a time. Everyone waits. Boring!
With multithreading, multiple cooks (threads) work on different dishes at the same time. Fast! Efficient!
graph TD A["Main Program"] --> B["Thread 1: Cook Pasta"] A --> C["Thread 2: Grill Steak"] A --> D["Thread 3: Make Salad"] B --> E["All Done Together!"] C --> E D --> E
Key Ideas:
- Process = The whole restaurant
- Thread = One cook in that restaurant
- Multithreading = Many cooks working at once
👨🍳 The Thread Class
Java gives you a ready-made cook uniform called the Thread class. Just put it on and start cooking!
Creating a Thread by Extending Thread Class
class MyCook extends Thread {
public void run() {
System.out.println("Cooking pasta!");
}
}
// Use it:
MyCook cook = new MyCook();
cook.start(); // Cook begins work!
What happens?
MyCookextendsThread(wears the cook uniform)run()contains the recipe (what to do)start()tells the cook to begin
🎯 Remember: Call
start(), notrun(). Why?start()creates a new cook.run()makes YOU do the work!
🎽 The Runnable Interface
What if your cook already has another job? Maybe they’re also a waiter? In Java, a class can only extend one parent. But it can wear many hats (implement many interfaces)!
Runnable is like a cooking badge. Anyone can wear it!
class MultitaskWorker implements Runnable {
public void run() {
System.out.println("I can cook AND serve!");
}
}
// Use it:
MultitaskWorker worker = new MultitaskWorker();
Thread t = new Thread(worker);
t.start();
Thread vs Runnable: Which to Choose?
| Thread Class | Runnable Interface |
|---|---|
Extend Thread |
Implement Runnable |
| Can’t extend other classes | Can extend other classes |
| Simple and direct | More flexible |
| Use for single-purpose threads | Use when class needs other parents |
🎯 Pro Tip: Most real projects use Runnable. It’s more flexible!
🚀 Creating and Starting Threads
Two ways to hire a cook:
Way 1: Extend Thread
class ChefThread extends Thread {
String dish;
ChefThread(String dish) {
this.dish = dish;
}
public void run() {
System.out.println("Making " + dish);
}
}
// Hire and start:
ChefThread chef = new ChefThread("Pizza");
chef.start();
Way 2: Implement Runnable
class DishTask implements Runnable {
String dish;
DishTask(String dish) {
this.dish = dish;
}
public void run() {
System.out.println("Cooking " + dish);
}
}
// Wrap in Thread and start:
Thread t = new Thread(new DishTask("Soup"));
t.start();
Way 3: Lambda (Quick & Easy!)
Thread t = new Thread(() -> {
System.out.println("Quick stir-fry!");
});
t.start();
🔄 Thread Lifecycle and States
Every cook goes through a journey in the kitchen:
graph TD NEW["NEW: Just Hired"] --> RUNNABLE["RUNNABLE: Ready to Cook"] RUNNABLE --> RUNNING["RUNNING: Cooking Now!"] RUNNING --> BLOCKED["BLOCKED: Waiting for Oven"] BLOCKED --> RUNNABLE RUNNING --> WAITING["WAITING: On Break"] WAITING --> RUNNABLE RUNNING --> TIMED_WAITING["TIMED_WAITING: 5-min Break"] TIMED_WAITING --> RUNNABLE RUNNING --> TERMINATED["TERMINATED: Shift Over"]
The 6 States Explained
| State | What’s Happening |
|---|---|
| NEW | Thread created, not started yet |
| RUNNABLE | Ready to run, waiting for CPU time |
| RUNNING | Currently executing code |
| BLOCKED | Waiting for a lock (someone else has the oven) |
| WAITING | Paused until someone wakes it up |
| TIMED_WAITING | Paused for a specific time |
| TERMINATED | Done! Thread finished its work |
Check a Thread’s State
Thread t = new Thread(() -> {
System.out.println("Working...");
});
System.out.println(t.getState()); // NEW
t.start();
System.out.println(t.getState()); // RUNNABLE
😴 Thread Sleep and Join
Sleep: Take a Nap!
Sometimes a cook needs a break:
Thread.sleep(2000); // Sleep for 2 seconds
Full Example:
class SleepyChef extends Thread {
public void run() {
System.out.println("Starting to cook...");
try {
Thread.sleep(3000); // 3 second nap
} catch (InterruptedException e) {
System.out.println("Woken up early!");
}
System.out.println("Done cooking!");
}
}
⚠️ Warning: Always wrap
sleep()in try-catch. Someone might interrupt the nap!
Join: Wait for Me!
What if the main chef needs to wait for helpers to finish?
Thread helper = new Thread(() -> {
System.out.println("Helper making sauce...");
try { Thread.sleep(2000); } catch (Exception e) {}
System.out.println("Sauce ready!");
});
helper.start();
helper.join(); // Wait for helper to finish
System.out.println("Now I can plate the dish!");
What join() does:
- Current thread stops and waits
- Waits until the joined thread finishes
- Then continues
graph TD A["Main Thread"] --> B["Start Helper"] B --> C["helper.join"] C --> D["Main Waits..."] E["Helper Working"] --> F["Helper Done"] F --> D D --> G["Main Continues"]
⚡ Thread Priority and Yield
Priority: Who’s More Important?
In a busy kitchen, some orders are VIP. Java lets you set priority!
thread.setPriority(Thread.MAX_PRIORITY); // 10 - VIP!
thread.setPriority(Thread.NORM_PRIORITY); // 5 - Normal
thread.setPriority(Thread.MIN_PRIORITY); // 1 - Can wait
Example:
Thread vipOrder = new Thread(() -> {
System.out.println("VIP dish!");
});
Thread normalOrder = new Thread(() -> {
System.out.println("Regular dish");
});
vipOrder.setPriority(Thread.MAX_PRIORITY);
normalOrder.setPriority(Thread.MIN_PRIORITY);
vipOrder.start();
normalOrder.start();
🎯 Reality Check: Priority is just a hint to the CPU. It doesn’t guarantee order!
Yield: “You Go First!”
A polite cook says: “I’ll pause. Someone else can work.”
Thread.yield();
Example:
class PoliteChef extends Thread {
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(getName() + " cooking step " + i);
Thread.yield(); // Let others have a turn
}
}
}
🎯 Remember:
yield()is a suggestion, not a command. The CPU decides!
👻 Daemon Threads
Imagine background helpers in the kitchen. They clean, restock, and do maintenance. When all the cooks go home, these helpers automatically leave too.
That’s a Daemon Thread!
Thread cleaner = new Thread(() -> {
while (true) {
System.out.println("Cleaning tables...");
try { Thread.sleep(1000); } catch (Exception e) {}
}
});
cleaner.setDaemon(true); // Mark as daemon
cleaner.start();
// When main thread ends, cleaner stops automatically!
Daemon vs Normal Threads
| Normal Thread | Daemon Thread |
|---|---|
| JVM waits for them to finish | JVM doesn’t wait |
| Must complete their work | Killed when no normal threads left |
| For important tasks | For background services |
setDaemon(false) (default) |
setDaemon(true) |
Common Uses for Daemon Threads:
- Garbage collection
- Auto-save features
- Background monitoring
- Cache cleanup
Thread t = new Thread(() -> {
System.out.println("Am I daemon? " +
Thread.currentThread().isDaemon());
});
t.setDaemon(true); // MUST set before start()!
t.start();
⚠️ Important: Set daemon status BEFORE calling
start()!
🎓 Quick Recap: The Kitchen Rules
- Multithreading = Many cooks working together
- Thread Class = Extend it for simple threads
- Runnable Interface = Implement for flexibility
- start() = Begins the thread (never call
run()directly!) - States = NEW → RUNNABLE → RUNNING → TERMINATED
- sleep() = Pause for a while
- join() = Wait for another thread to finish
- Priority = Suggest importance (1-10)
- yield() = Politely let others run
- Daemon = Background helper that auto-stops
🚀 You’ve Got This!
Threads might seem complex, but remember the kitchen:
- Program = Restaurant
- Threads = Cooks
- CPU = Head chef deciding who works when
Start simple. Create one thread. Then two. Soon you’ll be running a whole kitchen of threads working together!
Happy coding! 🎉
