Different ways to create Thread in Java?
meenakshi kalia
@ Wipro Lead Technical Solution Architect(GenAI) | Certified Scrum Master
In Java, there are several ways to create and manage threads. Here are the most common methods:
1. Extending the Thread Class
- You create a subclass of Thread and override its run() method.
- Call the start() method to begin the execution of the thread.
Example:
class MyThread extends Thread {
@Override
public void run() {
System.out.println("Thread is running!");
}
}
public class Main {
public static void main(String[] args) {
MyThread thread = new MyThread();
thread.start(); // Starts the thread
}
}
2. Implementing the Runnable Interface
- Create a class that implements the Runnable interface and define the run() method.
- Pass the Runnable object to a Thread object and call its start() method.
Example:
class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("Runnable thread is running!");
}
}
public class Main {
public static void main(String[] args) {
Thread thread = new Thread(new MyRunnable());
thread.start(); // Starts the thread
}
}
3. Using an Anonymous Inner Class
- You can create a thread using an anonymous implementation of the Runnable interface.
Example:
public class Main {
public static void main(String[] args) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Anonymous Runnable is running!");
}
});
thread.start();
}
}
4. Using a Lambda Expression (Java 8 and Later)
- Simplify thread creation using a lambda expression for the Runnable interface.
Example:
public class Main {
public static void main(String[] args) {
Thread thread = new Thread(() -> System.out.println("Lambda thread is running!"));
thread.start();
}
}
5. Using the ExecutorService Framework
- Use the ExecutorService to manage thread pools and execute tasks concurrently.
Example:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Main {
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(2);
executor.submit(() -> {
System.out.println("Task 1 is running!");
});
executor.submit(() -> {
System.out.println("Task 2 is running!");
});
executor.shutdown(); // Gracefully shuts down the executor
}
}
6. Using the Callable and Future Interfaces
- Use Callable for tasks that return a result and Future to retrieve the result.
Example:
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class Main {
public static void main(String[] args) throws Exception {
ExecutorService executor = Executors.newSingleThreadExecutor();
Callable<String> task = () -> {
Thread.sleep(1000); // Simulate some work
return "Callable thread result!";
};
Future<String> future = executor.submit(task);
System.out.println("Task submitted. Waiting for result...");
System.out.println("Result: " + future.get()); // Waits and retrieves the result
executor.shutdown();
}
}
7. Using Timer and TimerTask for Scheduled Execution
- Use Timer and TimerTask to schedule threads for delayed or periodic execution.
Example:
import java.util.Timer;
import java.util.TimerTask;
public class Main {
public static void main(String[] args) {
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
System.out.println("Timer task is running!");
}
}, 1000); // Executes after 1 second
}
}
8. Using ForkJoinPool for Parallelism (Java 7 and Later)
- Use ForkJoinPool for tasks that can be divided into smaller subtasks.
Example:
import java.util.concurrent.RecursiveAction;
import java.util.concurrent.ForkJoinPool;
class MyTask extends RecursiveAction {
@Override
protected void compute() {
System.out.println("ForkJoinPool task is running!");
}
}
public class Main {
public static void main(String[] args) {
ForkJoinPool pool = new ForkJoinPool();
pool.invoke(new MyTask());
pool.shutdown();
}
}
Comparison and Use Cases