Posted on: January 18, 2025 Posted by: rahulgite Comments: 0

In Java, there are several ways to create and manage threads. Here’s an overview of the primary methods:


1. Extending the Thread Class

  • You can create a class that extends the Thread class and overrides its run method.
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(); // Start the thread
}
}

2. Implementing the Runnable Interface

  • Create a class that implements the Runnable interface and pass it to a Thread object.
class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("Thread is running...");
}
}

public class Main {
public static void main(String[] args) {
Thread thread = new Thread(new MyRunnable());
thread.start();
}
}

3. Using an Anonymous Class

  • You can create a thread by directly instantiating Runnable as an anonymous class.
public class Main {
public static void main(String[] args) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Thread is running...");
}
});
thread.start();
}
}

4. Using Lambda Expressions (Java 8+)

  • Use a lambda expression to simplify thread creation.
public class Main {
public static void main(String[] args) {
Thread thread = new Thread(() -> System.out.println("Thread is running..."));
thread.start();
}
}

5. Using the Executor Framework (Recommended for Thread Pool Management)

  • Use the Executor framework to manage threads efficiently, especially for multiple tasks.
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.execute(() -> System.out.println("Task 1 is running..."));
executor.execute(() -> System.out.println("Task 2 is running..."));

executor.shutdown(); // Shutdown the executor
}
}

6. Using the Callable Interface and Future

  • Callable is similar to Runnable but allows returning a result or throwing an exception.
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 = () -> {
return "Task is completed!";
};

Future<String> future = executor.submit(task);

System.out.println(future.get()); // Get the result

executor.shutdown();
}
}

7. Using ForkJoinPool for Recursive Tasks (Java 7+)

  • Use for parallelism with tasks that can be divided into subtasks.
import java.util.concurrent.RecursiveTask;
import java.util.concurrent.ForkJoinPool;

class SumTask extends RecursiveTask<Integer> {
private int start, end;

public SumTask(int start, int end) {
this.start = start;
this.end = end;
}

@Override
protected Integer compute() {
if (end - start <= 10) {
int sum = 0;
for (int i = start; i <= end; i++) {
sum += i;
}
return sum;
} else {
int mid = (start + end) / 2;
SumTask leftTask = new SumTask(start, mid);
SumTask rightTask = new SumTask(mid + 1, end);

leftTask.fork();
rightTask.fork();

return leftTask.join() + rightTask.join();
}
}
}

public class Main {
public static void main(String[] args) {
ForkJoinPool pool = new ForkJoinPool();
SumTask task = new SumTask(1, 100);

int result = pool.invoke(task);
System.out.println("Sum: " + result);
}
}

Comparison of Thread Creation Methods in Java

MethodWhen to UseProsCons
Extending Thread ClassWhen simple thread creation is needed, and no other class needs to be extended.Easy to implement, direct thread control.Cannot extend any other class due to Java’s single inheritance limitation.
Implementing Runnable InterfaceWhen a task needs to be executed in a separate thread without modifying thread behavior.More flexible, allows extending other classes.Requires explicit creation of Thread instance.
Implementing Callable InterfaceWhen the thread needs to return a result or throw a checked exception.Supports returning values and handling exceptions.More complex than Runnable due to Future and ExecutorService usage.
Using ThreadPool (ExecutorService)When managing multiple threads efficiently is needed.Manages resources efficiently, improves performance.Requires careful management to avoid resource leaks.
Using Fork/Join FrameworkWhen dealing with large recursive tasks that can be broken down into subtasks.Optimized for parallel processing, improves performance on multi-core CPUs.More complex to implement, best suited for divide-and-conquer problems.
Using Virtual Threads (Project Loom – Java 19+)When a large number of lightweight threads are needed for high concurrency.Low resource overhead, simplifies concurrent programming.Not yet widely adopted, still evolving.

This table provides an overview of various thread creation approaches in Java, helping developers choose the best method based on their use case.

Leave a Comment