In Java, Managing threads manually can be a complex task because it involves thread creation, synchronization and also thread lifecycle management. to simplifying the Java Executor Framework, part of the java.util.concurrent
package, provides a robust solution to handle these complexities with ease.
It abstracts thread management and allows developers to focus on task execution. So in this blog we explores the Executor Framework, its components, and practical usage with examples.
What is the Executor Framework?
The Executor Framework is a high-level API designed to manage threads and execute tasks asynchronously. Instead of directly creating and managing Thread
objects, you can use the framework to submit tasks and let it handle the underlying thread pool. At its core, the framework revolves around the Executor
interface, with ExecutorService
extending it to offer advanced features.
Key Components
-
Executor
: The base interface defining a simple task execution mechanism. -
ExecutorService
: An extension ofExecutor
that provides methods to manage task submission, shutdown, and thread pools. -
ThreadPoolExecutor
: A concrete implementation that manages a pool of threads, configurable with core and maximum pool sizes. -
ScheduledExecutorService
: A specialized service for scheduling tasks to run after a delay or at fixed intervals. -
ForkJoinPool
: Optimized for tasks that can be recursively split into smaller subtasks.
Why Use the Executor Framework?
- Simplified Thread Management: No need to manually create or destroy threads.
- Thread Reuse: Reduces overhead by reusing threads from a pool.
-
Flexible Task Submission: Supports
Runnable
andCallable
tasks withFuture
results. -
Controlled Shutdown: Offers graceful termination with
shutdown()
andshutdownNow()
.
How It Works
The Executor Framework uses a thread pool to manage tasks. Submitters send tasks to the ExecutorService
, which queues them in a task queue (e.g., ArrayBlockingQueue
or LinkedBlockingQueue
). A pool of threads picks tasks from the queue and executes them. This process is illustrated by the diagram showing task submission, queuing, and execution by threads.
Configuring a ThreadPoolExecutor
A ThreadPoolExecutor
can be customized with parameters:
- Core Pool Size: Minimum number of threads kept alive (e.g., 4).
- Maximum Pool Size: Maximum number of threads that can be created (e.g., 7).
- Keep Alive Time: Idle time after which extra threads are terminated (e.g., 2 seconds).
-
Task Queue: A queue to hold pending tasks (e.g.,
LinkedBlockingQueue
).
Example configuration:
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
4, // corePoolSize
7, // maximumPoolSize
2, // keepAliveTime (seconds)
TimeUnit.SECONDS,
new LinkedBlockingQueue<>()
);
Submitting Tasks
Tasks can be submitted in two main ways:
-
execute(Runnable)
: Fire-and-forget execution, suitable for tasks without return values. -
submit(Runnable/Callable)
: Returns aFuture
object to track task completion or retrieve results.
Example: Submitting a Runnable Task
threadPoolExecutor.submit(new Runnable() {
@Override
public void run() {
System.out.println("Task 1(4Seconds) Started by Thread Name : " + Thread.currentThread().getName());
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("Task 1(4Seconds) Ended by Thread Name : " + Thread.currentThread().getName());
}
});
This code submits a task that sleeps for 4 seconds, printing the thread name before and after.
Shutting Down the Executor
To terminate the thread pool gracefully:
-
shutdown()
: Initiates a shutdown, completing ongoing tasks but not accepting new ones. -
shutdownNow()
: Attempts to stop all tasks immediately, interrupting active threads.
Example:
threadPoolExecutor.shutdown();
Read complete blog here : https://www.codingshuttle.com/blogs/java-executor-framework-tutorial-simplifying-multithreading-with-executor-service/
Top comments (0)