✅ What is a Thread in Java?
A thread in Java is a lightweight sub-process — the smallest unit of execution. It allows multiple tasks to run concurrently within a program, sharing the same memory space.
Java threads are part of the java.lang.Thread class and can be used to:
-
Perform background tasks
-
Increase responsiveness
-
Utilize CPU more efficiently on multicore systems
✅ What is Multithreading?
Multithreading is the process of executing two or more threads concurrently within a single Java program. It enhances the performance of applications by utilizing CPU more efficiently and enabling tasks to run in parallel.
🔄 Characteristics:
-
Threads share the same memory.
-
Requires synchronization to avoid race conditions.
-
Helps in parallel execution and responsive applications.
✅ Real-world Uses of Multithreading in Projects
| Use Case | Example |
|---|---|
| Web Servers | Handling multiple HTTP requests in parallel (Spring Boot, Tomcat) |
| Background Processing | Asynchronous email sending, file uploads, or logging |
| Batch Processing | Processing large files or DB records concurrently |
| UI Responsiveness | In desktop apps (Swing/JavaFX), long-running tasks run in background threads |
| Real-time Data Processing | Kafka consumers reading streams on separate threads |
| Microservices | Running parallel tasks (e.g., fetching user info from multiple services) |
How many ways create threads in java 8
In Java 8, you can create threads in several ways. The most common approaches are:
1. Extending the Thread Class
You can create a thread by extending the Thread class and overriding its run() method.
class MyThread extends Thread {
public void run() {
System.out.println("Thread running...");
}
}
public class Main {
public static void main(String[] args) {
MyThread thread = new MyThread();
thread.start(); // Start the thread
}
}
You can create a thread by extending the Thread class and overriding its run() method.
class MyThread extends Thread {
public void run() {
System.out.println("Thread running...");
}
}
public class Main {
public static void main(String[] args) {
MyThread thread = new MyThread();
thread.start(); // Start the thread
}
}
2. Implementing the Runnable Interface
Implementing Runnable allows more flexibility since the class can still extend another class.
class MyRunnable implements Runnable {
public void run() {
System.out.println("Thread running...");
}
}
public class Main {
public static void main(String[] args) {
Thread thread = new Thread(new MyRunnable());
thread.start();
}
}
Implementing Runnable allows more flexibility since the class can still extend another class.
class MyRunnable implements Runnable {
public void run() {
System.out.println("Thread running...");
}
}
public class Main {
public static void main(String[] args) {
Thread thread = new Thread(new MyRunnable());
thread.start();
}
}
3. Using Lambda Expressions (Java 8 Feature)
Java 8 introduced lambda expressions, simplifying the Runnable implementation.
public class Main {
public static void main(String[] args) {
Thread thread = new Thread(() -> System.out.println("Thread running..."));
thread.start();
}
}
Java 8 introduced lambda expressions, simplifying the Runnable implementation.
public class Main {
public static void main(String[] args) {
Thread thread = new Thread(() -> System.out.println("Thread running..."));
thread.start();
}
}
4. Using the ExecutorService (Thread Pool)
Java provides the ExecutorService framework to manage thread pools efficiently.
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("Thread running..."));
executor.shutdown(); // Shutdown the executor
}
}
Java provides the ExecutorService framework to manage thread pools efficiently.
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("Thread running..."));
executor.shutdown(); // Shutdown the executor
}
}
5. Using the Callable and Future Interface
If you need a return value from a thread, use Callable instead of Runnable.
import java.util.concurrent.*;
public class Main {
public static void main(String[] args) {
ExecutorService executor = Executors.newSingleThreadExecutor();
Callable<String> task = () -> {
Thread.sleep(2000); // Simulating a delay
return "Task completed!";
};
Future<String> future = executor.submit(task);
try {
System.out.println("Waiting for the result...");
String result = future.get(); // Blocks until the result is available
System.out.println("Result: " + result);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
} finally {
executor.shutdown(); // Properly shut down the executor
}
}
}
If you need a return value from a thread, use Callable instead of Runnable.
import java.util.concurrent.*;
public class Main {
public static void main(String[] args) {
ExecutorService executor = Executors.newSingleThreadExecutor();
Callable<String> task = () -> {
Thread.sleep(2000); // Simulating a delay
return "Task completed!";
};
Future<String> future = executor.submit(task);
try {
System.out.println("Waiting for the result...");
String result = future.get(); // Blocks until the result is available
System.out.println("Result: " + result);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
} finally {
executor.shutdown(); // Properly shut down the executor
}
}
}
6. Using CompletableFuture (Java 8 Feature)
Java 8 introduced CompletableFuture for async programming.
import java.util.concurrent.CompletableFuture;
public class Main {
public static void main(String[] args) {
CompletableFuture.runAsync(() -> System.out.println("Thread running..."));
}
}
Each approach has its own use case, depending on whether you need a simple thread, a return value, or a managed thread pool.
Java 8 introduced CompletableFuture for async programming.
import java.util.concurrent.CompletableFuture;
public class Main {
public static void main(String[] args) {
CompletableFuture.runAsync(() -> System.out.println("Thread running..."));
}
}
✅ Summary Table
| Feature | Thread | Runnable | Executor | Callable | CompletableFuture |
|---|---|---|---|---|---|
| Return Value | ❌ | ❌ | ❌/✅ | ✅ | ✅ |
| Java 8 Friendly | ❌ | ✅ | ✅ | ✅ | ✅ |
| Use for Thread Pools | ❌ | ✅ | ✅ | ✅ | ✅ |
| Async Style | ❌ | ❌ | ✅ | ✅ | ✅ |
| Lambda Support | ❌ | ✅ | ✅ | ✅ | ✅ |
Where to Use Multithreading in Your Spring Boot Project?
Multithreading is beneficial in various scenarios of a Spring Boot application:
1. Asynchronous Task Execution
Use @Async to run tasks in a separate thread.
✅ Use Case: Long-running operations like sending emails, file processing, or background jobs.
2. Parallel Processing in REST APIs
Use CompletableFuture to return responses without blocking.
✅ Use Case: Fetching data from multiple sources (e.g., APIs, databases) in parallel.
3. Handling Multiple User Requests (Thread Pooling)
Spring Boot uses ExecutorService for thread pooling.
✅ Use Case: Optimizing performance for high-traffic APIs.
4. Multi-threaded Batch Processing (Spring Batch)
Spring Batch executes tasks in chunks using multiple threads.
✅ Use Case: Large dataset processing, scheduled jobs, and ETL (Extract, Transform, Load) tasks.
5. Concurrent Database Operations
Using @Transactional with multithreading ensures data consistency.
✅ Use Case: Parallel processing of bulk database updates.
Conclusion
Multithreading is a vital concept in Java programming, enabling the concurrent execution of tasks to fully utilize system resources and improve application responsiveness. It plays a key role in:
-
🔄 Concurrency: Efficiently managing multiple tasks at the same time.
-
⚡ Parallelism: Taking advantage of multi-core processors for faster execution.
-
🚀 Responsiveness: Ensuring that applications remain smooth and non-blocking during long-running operations.
In high-performance Java applications, multithreading is essential for:
-
Optimizing resource utilization
-
Enhancing throughput and scalability
-
Supporting real-time and asynchronous processing
In modern Spring Boot projects, multithreading is widely applied for:
-
Handling multiple HTTP requests concurrently
-
Running background tasks (e.g., email sending, data processing)
-
Performing parallel database operations to reduce latency
By using Java’s threading tools—such as Thread, Runnable, ExecutorService, Callable, and CompletableFuture—developers can write more efficient, robust, and scalable applications.
In Java, thread priorities determine the relative importance of threads, helping the thread scheduler decide which thread to run first when multiple threads are eligible.
2) Thread Priority in Java
-
Every thread in Java has a priority, an integer between 1 (MIN_PRIORITY) and 10 (MAX_PRIORITY).
-
The default priority is 5 (NORM_PRIORITY).
🔢 Priority Constants in Thread class:
🔧 Setting and Getting Priority:
⚙️ Example with Priority:
🧠Output (order is not guaranteed):
The JVM thread scheduler behavior depends on the OS. Java thread priority is a hint, not a strict rule. Don't rely on it for correctness in production code.
🔒 Summary:
| Feature | Value |
|---|---|
| Range | 1 to 10 |
| Default Priority | 5 (NORM_PRIORITY) |
| Used for | Thread scheduling hints |
| OS-dependent | ✅ Yes |
No comments:
Post a Comment