5.
5 Thread Objects, Defining and Starting a Thread
Threads allow concurrent execution of tasks in Java, improving application
performance. Java provides two ways to create and start threads:
1. Extending the Thread class
2. Implementing the Runnable interface (Recommended for better flexibility)
1. Creating a Thread by Extending the Thread Class
We create a thread by extending the Thread class and overriding the run() method.
Example:
class MyThread extends Thread {
public void run() { // Overriding run() method
for (int i = 1; i <= 5; i++) {
System.out.println("Thread running: " + i);
try {
Thread.sleep(500); // Pause for 500 milliseconds
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class ThreadExample {
public static void main(String[] args) {
MyThread t1 = new MyThread(); // Creating thread object
t1.start(); // Starting the thread
}
}
✅ Output (Runs independently from main() thread):
Thread running: 1
Thread running: 2
Thread running: 3
Thread running: 4
Thread running: 5
🚀 Key Points:
run() method contains the code executed by the thread.
start() method starts the execution of a new thread.
Thread.sleep(milliseconds) pauses execution for a while.
2. Creating a Thread by Implementing the Runnable Interface (Recommended)
The Runnable interface is preferred because it allows multiple threads to share the
same object.
Example:
class MyRunnable implements Runnable {
public void run() {
for (int i = 1; i <= 5; i++) {
System.out.println("Runnable Thread: " + i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class RunnableExample {
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable(); // Create Runnable object
Thread t1 = new Thread(myRunnable); // Create Thread with Runnable
t1.start(); // Start the thread
}
}
✅ Output:
Runnable Thread: 1
Runnable Thread: 2
Runnable Thread: 3
Runnable Thread: 4
Runnable Thread: 5
🚀 Advantages of Runnable:
Better flexibility (allows multiple threads to share the same task).
Avoids single inheritance limitation (since Java does not support multiple
inheritance).
Improved resource sharing.
3. Running Multiple Threads
We can create multiple threads that run simultaneously.
Example:
class MyTask implements Runnable {
private String name;
MyTask(String name) {
this.name = name;
}
public void run() {
for (int i = 1; i <= 3; i++) {
System.out.println(name + " - Count: " + i);
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class MultiThreadExample {
public static void main(String[] args) {
Thread t1 = new Thread(new MyTask("Thread-1"));
Thread t2 = new Thread(new MyTask("Thread-2"));
t1.start();
t2.start();
}
}
✅ Output (May vary due to concurrent execution):
Thread-1 - Count: 1
Thread-2 - Count: 1
Thread-1 - Count: 2
Thread-2 - Count: 2
Thread-1 - Count: 3
Thread-2 - Count: 3
🚀 Key Points:
Multiple threads execute simultaneously.
Execution order is unpredictable (depends on CPU scheduling).
4. Thread Lifecycle in Java
A thread in Java goes through several states:
State Description
NEW Thread is created but not started (new Thread()).
RUNNABLE Thread is started and ready to run.
RUNNING Thread is currently executing (run() method).
BLOCKED Thread is waiting for a resource (e.g., lock).
WAITING Thread is waiting indefinitely for another thread’s signal.
TIMED_WAITING Thread is waiting for a specific amount of time (Thread.sleep()).
TERMINATED Thread has finished execution.
5. Using join() to Wait for Thread Completion
The join() method ensures that the main thread waits for another thread to finish before
continuing.
Example:
class Worker extends Thread {
private String name;
Worker(String name) {
this.name = name;
}
public void run() {
for (int i = 1; i <= 3; i++) {
System.out.println(name + " is working... " + i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class JoinExample {
public static void main(String[] args) {
Worker t1 = new Worker("Worker-1");
Worker t2 = new Worker("Worker-2");
t1.start();
try {
t1.join(); // Main thread waits until t1 finishes
} catch (InterruptedException e) {
e.printStackTrace();
}
t2.start(); // t2 starts only after t1 completes
}
}
✅ Output (t2 starts only after t1 finishes):
Worker-1 is working... 1
Worker-1 is working... 2
Worker-1 is working... 3
Worker-2 is working... 1
Worker-2 is working... 2
Worker-2 is working... 3
🚀 Key Points:
join() ensures Worker-2 starts only after Worker-1 completes.
6. Thread Priorities
Java threads have priority levels (1 to 10):
Thread.MIN_PRIORITY = 1
Thread.NORM_PRIORITY = 5 (Default)
Thread.MAX_PRIORITY = 10
Example:
class PriorityThread extends Thread {
PriorityThread(String name) {
super(name);
}
public void run() {
System.out.println(getName() + " Priority: " + getPriority());
}
}
public class ThreadPriorityExample {
public static void main(String[] args) {
PriorityThread t1 = new PriorityThread("Low Priority");
PriorityThread t2 = new PriorityThread("High Priority");
t1.setPriority(Thread.MIN_PRIORITY);
t2.setPriority(Thread.MAX_PRIORITY);
t1.start();
t2.start();
}
}
✅ Output (Thread with higher priority may execute first):
High Priority Priority: 10
Low Priority Priority: 1
🚀 Key Point: Priority does not guarantee execution order (depends on OS scheduling).
7. Daemon Threads
A daemon thread runs in the background (e.g., Garbage Collector).
Use setDaemon(true) before starting the thread.
class DaemonTask extends Thread {
public void run() {
while (true) {
System.out.println("Daemon Thread Running...");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class DaemonExample {
public static void main(String[] args) {
DaemonTask daemon = new DaemonTask();
daemon.setDaemon(true);
daemon.start();
System.out.println("Main thread finishes...");
}
}