This project demonstrates the implementation of ThreadPoolTaskExecutor in a Spring Boot application. It provides RESTful APIs to trigger asynchronous execution of tasks. The project includes two services:
- Order Service – Handles order processing asynchronously.
- Forgot Password Service – Manages forgot password requests asynchronously.
ThreadPoolTaskExecutor is a class provided by Spring Framework to handle asynchronous tasks in Spring. It is a powerful asynchronous task execution mechanism that allows you to manage a pool of worker threads efficiently. The ThreadPoolTaskExecutor is configured with various properties to optimize performance:
-
corePoolSize – The number of threads to keep in the pool, even if they are idle.
- If the number of threads is less than the core, a new thread is created to handle the task.
- If the number of threads is greater than the core, the task is added to the queue.
-
maxPoolSize – The maximum number of threads to allow in the pool.
- This limit prevents the thread pool from creating too many threads, which could overwhelm the system.
- When tasks are submitted, the thread pool starts with corePoolSize threads.
- If all corePoolSize threads are busy, new tasks are added to the queue.
- If the queue is full, additional threads are created up to maxPoolSize.
- Once maxPoolSize is reached, new tasks cannot be executed immediately and are handled based on the rejection policy.
-
queueCapacity – The maximum number of tasks that can be queued.
- It acts as a buffer that holds tasks waiting to be executed.
- If all corePoolSize threads are busy, the task goes into the queue (if there is space).
- If the number of tasks exceeds the queue capacity, additional threads are created up to maxPoolSize.
-
threadNamePrefix – The prefix to use for the names of the threads.
-
allowCoreThreadTimeout
- Whether to allow core threads to time out and terminate if no tasks arrive within the keepAliveSeconds time.
- By default, core threads are always kept alive, but enabling allowCoreThreadTimeOut(true) allows them to be removed when not needed.
- If allowCoreThreadTimeOut(false), core threads stay alive forever, even if idle.
- If allowCoreThreadTimeOut(true), core threads are removed if they remain idle for keepAliveSeconds.
- It only works if keepAliveSeconds is set.
- This can help reduce resource consumption when the number of tasks is low.
-
keepAliveSeconds
- When the number of threads is greater than the core, this is the maximum time that excess idle threads will wait for new tasks before terminating.
- Controls how long extra threads stay idle before being removed.
-
rejectedExecutionHandler – The handler to use when the executor cannot accept a task.
- There are four types of RejectedExecutionHandler:
- AbortPolicy: Throws a RejectedExecutionException.
- CallerRunsPolicy: Executes the task on the caller's thread.
- DiscardPolicy: Discards the task silently.
- DiscardOldestPolicy: Discards the oldest task in the queue and adds the new task.
- There are four types of RejectedExecutionHandler:
-
waitForTasksToCompleteOnShutdown
- Whether to wait for scheduled tasks to complete on shutdown.
-
awaitTerminationSeconds – The maximum time to wait for the executor to terminate.
@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(corePoolSize);
executor.setMaxPoolSize(maxPoolSize);
executor.setQueueCapacity(queueCapacity);
executor.setThreadNamePrefix(threadNamePrefix);
executor.setAllowCoreThreadTimeOut(allowCoreThreadTimeout);
executor.setKeepAliveSeconds(keepAliveSeconds);
executor.setRejectedExecutionHandler(getRejectedExecutionHandler(rejectedExecutionHandler));
executor.setWaitForTasksToCompleteOnShutdown(waitForTasksToCompleteOnShutdown);
executor.setAwaitTerminationSeconds(awaitTerminationSeconds);
executor.initialize();
return executor;
}
}The technology used in this project are:
Spring Boot Starter Web– Provides essential components for building RESTful APIs.ThreadPoolTaskExecutor– Manages a pool of worker threads efficiently for executing tasks asynchronously.Spring Retry– Handles retry mechanisms for failed operations.
The project is organized into the following package structure:
async-executor/
│── src/main/java/com/yoanesber/spring/async_executor/
│ ├── 📂async/ # Defines task executor.
│ ├── 📂config/ # Configures ThreadPoolTaskExecutor (corePoolSize, maxPoolSize, queueCapacity, etc.).
│ ├── 📂controller/ # Contains REST controllers handling Forgot Password and Order Service requests.
│ ├── 📂dto/ # Data Transfer Objects (DTOs) for request/response payloads.
│ ├── 📂entity/ # Contains Order and OrderDetail classes representing order data.
│ ├── 📂service/ # Business logic layer
│ │ ├── 📂impl/ # Implementation of servicesConfiguration values are stored in .env.development and referenced in application.properties.
Example .env.development file content:
# Application properties
APP_PORT=8081
SPRING_PROFILES_ACTIVE=development
# ThreadPoolTaskExecutor properties
ASYNC_CORE_POOL_SIZE=5
ASYNC_MAX_POOL_SIZE=10
ASYNC_QUEUE_CAPACITY=100
ASYNC_THREAD_NAME_PREFIX=async-
ASYNC_ALLOW_CORE_THREAD_TIMEOUT=true
ASYNC_KEEP_ALIVE_SECONDS=10
ASYNC_REJECTED_EXECUTION_HANDLER=CALLER_RUNS
ASYNC_WAIT_FOR_TASKS_TO_COMPLETE_ON_SHUTDOWN=true
ASYNC_AWAIT_TERMINATION_SECONDS=10Example application.properties file content:
# Application properties
spring.application.name=async-executor
server.port=${APP_PORT}
spring.profiles.active=${SPRING_PROFILES_ACTIVE}
# ThreadPoolTaskExecutor properties
async.executor.core.pool.size=${ASYNC_CORE_POOL_SIZE}
async.executor.max.pool.size=${ASYNC_MAX_POOL_SIZE}
async.executor.queue.capacity=${ASYNC_QUEUE_CAPACITY}
async.executor.thread.name.prefix=${ASYNC_THREAD_NAME_PREFIX}
async.executor.allow.core.thread.timeout=${ASYNC_ALLOW_CORE_THREAD_TIMEOUT}
async.executor.keep.alive.seconds=${ASYNC_KEEP_ALIVE_SECONDS}
async.executor.rejected.execution.handler=${ASYNC_REJECTED_EXECUTION_HANDLER}
async.executor.wait.for.tasks.to.complete.on.shutdown=${ASYNC_WAIT_FOR_TASKS_TO_COMPLETE_ON_SHUTDOWN}
async.executor.await.termination.seconds=${ASYNC_AWAIT_TERMINATION_SECONDS}A step by step series of examples that tell you how to get a development env running.
- Ensure you have Git installed on your Windows machine, then clone the repository to your local environment:
git clone https://github.com/yoanesber/Spring-Boot-ThreadPoolTaskExecutor.git
cd Spring-Boot-ThreadPoolTaskExecutor- Build and run the application
mvn spring-boot:runPOST http://localhost:8081/api/v1/order/process/{orderId} - Process order asynchronously.
Successful Response:
Order processed successfullyPOST http://localhost:8081/api/v1/password/forgot-password - Initiate forgot password request (async processing).
Request Body:
{
"email": "jhonny@myemail.com"
}Successful Response:
Password reset email sent successfully- Scheduled Tasks using ThreadPoolTaskScheduler GitHub Repository, check out Spring Boot Scheduled Tasks with ThreadPoolTaskScheduler.