A detailed guide based on my experience and best practices.
In my journey, I learned that Multi-threading is crucial. It lets my programs handle multiple tasks at the same time (or concurrently), which is essential for performance. Every time I create a thread, I'm creating a small, independent unit of work.
No matter which method I choose, the actual work always goes inside the run()
method. I always start a thread by calling start(), never run()
directly.
Thread ClassThis is the simplest way, but I try to avoid it unless necessary, as it consumes my single inheritance option.
java.lang.Thread.public void run() method to put my task logic there.start() method on it.// My first method to define a thread
class MyThread extends Thread {
public void run() {
System.out.println("Task 1: Running by extending Thread.");
}
}
// Starting it up
public class Main {
public static void main(String[] args) {
MyThread t1 = new MyThread();
t1.start(); // Initiates the thread and calls run()
}
}
Runnable Interface 🌟 (My Preferred
Method)This is my expert judgment on the better option. Since Java doesn't support multiple
inheritance, implementing Runnable keeps my class free to extend another
superclass, which is invaluable for code structure and reuse.
java.lang.Runnable interface.public void run() method (the task).Thread class, passing my Runnable object to its
constructor.start()** method on the **Thread object**.// My task, separated from the Thread control
class MyRunnable implements Runnable {
public void run() {
System.out.println("Task 2: Running by implementing Runnable.");
}
}
// Starting it up
public class Main {
public static void main(String[] args) {
MyRunnable task = new MyRunnable();
Thread t2 = new Thread(task); // Thread object given the task
t2.start(); // This is what I call to begin execution
}
}
I view a thread as a living entity that moves through five distinct states from creation to destruction. I must understand these states to properly manage my programs.
| State | My Action / How it Gets There | What it Means to Me |
|---|---|---|
| 1. New (Born) | When I use the new keyword (e.g.,
new Thread()). |
The thread object is created but is **not active** yet. |
| 2. Runnable | When I call the **start()** method. |
The thread is **ready to run** and is waiting for the CPU. |
| 3. Running | The OS scheduler gives the thread CPU time. | The thread is **executing its run() method code**.
|
| 4. Blocked/Waiting/Timed Waiting | When I call sleep(), or the thread is
waiting for a **lock** (synchronized block) or another thread (join(),
wait()). |
The thread is **temporarily inactive** and cannot run until its waiting condition is resolved. |
| 5. Terminated (Dead) | When the thread's **run() method
completes naturally** or an exception is thrown. |
The thread is finished. I **cannot restart it**. |
Understanding these states helps me manage thread behavior and avoid common pitfalls like deadlocks or resource contention.
stop(), suspend(), or
resume(). They can crash my application or cause severe deadlocks.
stop(). Instead, I use a **flag variable** (a
volatile boolean) that the thread checks in its loop. When I want the thread to stop, I set
the flag to false, allowing the thread to exit its run() method cleanly.suspend() and resume(). For controlled
communication between threads, I use the safer **inter-thread communication methods** like
wait() and notify()/notifyAll().Thread object if I need to execute the task
again.