Concurrency is key to building scalable Java applications. The Executor
framework in Java allows you to manage threads efficiently using thread pools. This article covers everything you need to know about ThreadPool and Executors with working code snippets.
π§΅ What is a ThreadPool?
A ThreadPool manages a pool of worker threads, allowing tasks to be reused instead of creating new threads every time. This improves performance and resource utilization.
β Why Avoid new Thread()
?
Using new Thread()
for each task can:
- π§ Cause high memory usage
- β‘οΈ Add overhead due to frequent thread creation
- π¨ Lead to resource exhaustion
π οΈ Java Executors Overview
1. Executor
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
public class SimpleExecutorExample {
public static void main(String[] args) {
Executor executor = Executors.newSingleThreadExecutor();
executor.execute(() -> System.out.println("Executed by: " + Thread.currentThread().getName()));
}
}
2. ExecutorService
import java.util.concurrent.*;
public class ExecutorServiceExample {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(2);
executorService.submit(() -> {
System.out.println("Task 1 by " + Thread.currentThread().getName());
});
executorService.submit(() -> {
System.out.println("Task 2 by " + Thread.currentThread().getName());
});
executorService.shutdown();
}
}
3. ThreadPoolExecutor
import java.util.concurrent.*;
public class CustomThreadPoolExecutorExample {
public static void main(String[] args) {
ThreadPoolExecutor executor = new ThreadPoolExecutor(
2, 4, 60L, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(2),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy()
);
for (int i = 0; i < 6; i++) {
int taskNumber = i;
executor.submit(() -> {
System.out.println("Task " + taskNumber + " executed by " + Thread.currentThread().getName());
});
}
executor.shutdown();
}
}
π Built-in Executor Types
FixedThreadPool
ExecutorService fixedPool = Executors.newFixedThreadPool(3);
- Fixed number of threads, reuses them
CachedThreadPool
ExecutorService cachedPool = Executors.newCachedThreadPool();
- Dynamically adjusts thread count
SingleThreadExecutor
ExecutorService singleThread = Executors.newSingleThreadExecutor();
- Executes tasks sequentially using a single thread
ScheduledThreadPool
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);
scheduler.schedule(() -> {
System.out.println("Delayed task executed by " + Thread.currentThread().getName());
}, 3, TimeUnit.SECONDS);
π Custom ThreadPoolExecutor
ExecutorService customExecutor = new ThreadPoolExecutor(
2, 4, 60L, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(10),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.CallerRunsPolicy()
);
Rejection Policies:
-
AbortPolicy
β throws exception -
CallerRunsPolicy
β runs task in caller thread -
DiscardPolicy
β silently discards -
DiscardOldestPolicy
β discards oldest task
π¦ Shutting Down Executors
executorService.shutdown();
try {
if (!executorService.awaitTermination(60, TimeUnit.SECONDS)) {
executorService.shutdownNow();
}
} catch (InterruptedException e) {
executorService.shutdownNow();
}
π Real-World Example: Parallel Task Execution
import java.util.concurrent.*;
import java.util.*;
public class FileProcessorExample {
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(3);
List<String> files = Arrays.asList("file1.txt", "file2.txt", "file3.txt", "file4.txt");
for (String file : files) {
executor.submit(() -> {
System.out.println("Processing " + file + " in thread " + Thread.currentThread().getName());
try {
Thread.sleep(1000); // simulate delay
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
}
executor.shutdown();
}
}
β Best Practices
- Always shut down the executor
- Prefer bounded queues for resource control
- Use
ThreadPoolExecutor
for advanced tuning - Monitor pool stats (active threads, queue size)
π€ Interview Questions
- Difference between
Executor
andExecutorService
? - What happens if the task queue is full?
- When to use which rejection policy?
- Fixed vs Cached ThreadPool?
- How to handle exceptions in executor tasks?
π TL;DR Summary
Type | Thread Count | Use Case |
---|---|---|
FixedThreadPool | Fixed | CPU-bound tasks |
CachedThreadPool | Dynamic | Short-lived tasks |
SingleThreadExecutor | 1 | Order-sensitive tasks |
ScheduledThreadPool | Fixed | Periodic task scheduling |
π Coming Next
- β¨
CompletableFuture
and async chaining - β‘ Performance tuning with real metrics
- π Spring Boot + Async Tasks using
@Async
Stay tuned!
Top comments (0)