Mastering AsyncTask Orchestration in Spring Boot with asyncTool
This guide shows how to integrate the asyncTool library into a Spring Boot project, configure custom thread pools, understand its core interfaces, and use code examples to build serial, parallel, and mixed task workflows with full monitoring, fault tolerance, and performance optimizations.
Integration into Spring Boot
1. Add Dependency
Add the asyncTool dependency to the project's pom.xml:
<dependency>
<groupId>com.jd.platform</groupId>
<artifactId>asyncTool</artifactId>
<version>{version}</version>
</dependency>2. Configure Thread Pool
asyncTool manages an internal pool, but you can supply a custom Executor for finer control. Two approaches are shown.
Custom Thread Pool
@Configuration
@EnableAsync // enable async execution
public class TaskExecutePool {
@Autowired
private TaskThreadPoolConfig config;
@Bean
public Executor myTaskAsyncPool() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(config.getCorePoolSize()); // core size
executor.setMaxPoolSize(config.getMaxPoolSize()); // max size
executor.setQueueCapacity(config.getQueueCapacity()); // queue capacity
executor.setKeepAliveSeconds(config.getKeepAliveSeconds()); // keep‑alive time
executor.setThreadNamePrefix("MyExecutor-"); // thread name prefix
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); // rejection policy
executor.initialize();
return executor;
}
}Modify Native Spring Async Thread Pool
@Configuration
@EnableAsync // enable async execution
public class NativeAsyncTaskExecutePool implements AsyncConfigurer {
@Autowired
private TaskThreadPoolConfig config;
@Bean
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(config.getCorePoolSize());
executor.setMaxPoolSize(config.getMaxPoolSize());
executor.setQueueCapacity(config.getQueueCapacity());
executor.setKeepAliveSeconds(config.getKeepAliveSeconds());
executor.setThreadNamePrefix("MyExecutor2-");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return (ex, method, objects) -> {
log.error("==========================" + ex.getMessage() + "=======================", ex);
log.error("exception method:" + method.getName());
};
}
}Core Interfaces
IWorker Interface
action(T object, Map<String, WorkerWrapper> allWrappers): core task logic; object is the input, allWrappers provides access to other tasks' results. defaultValue(): value returned when the task times out or throws an exception.
ICallback Interface
begin(): called when the task starts.
result(boolean success, T param, WorkResult<V> workResult): callback with execution outcome; success indicates success, param is the input, workResult holds the result.
WorkerWrapper Class
id: unique identifier of the task. param: input parameter. worker: concrete implementation of the task. callback: callback implementation. depend: defines strong or weak dependencies to control execution order. next: defines subsequent tasks.
Detailed Usage and Examples
Serial Tasks
Tasks are executed one after another in the defined order.
// Task A
WorkerWrapper wrapperA = new WorkerWrapper.Builder<Integer, Integer>()
.id("workerA")
.worker(new WorkerA())
.callback(new WorkerA())
.param(1)
.build();
// Task B depends on A
WorkerWrapper wrapperB = new WorkerWrapper.Builder<Integer, Integer>()
.id("workerB")
.worker(new WorkerB())
.callback(new WorkerB())
.param(2)
.depend(wrapperA)
.build();
// Task C depends on B
WorkerWrapper wrapperC = new WorkerWrapper.Builder<Integer, Integer>()
.id("workerC")
.worker(new WorkerC())
.callback(new WorkerC())
.param(3)
.depend(wrapperB)
.build();
Async.beginWork(1000, wrapperA);Parallel Tasks
Multiple tasks run concurrently.
// Task A
WorkerWrapper wrapperA = new WorkerWrapper.Builder<Integer, Integer>()
.id("workerA")
.worker(new WorkerA())
.callback(new WorkerA())
.param(1)
.build();
// Task B
WorkerWrapper wrapperB = new WorkerWrapper.Builder<Integer, Integer>()
.id("workerB")
.worker(new WorkerB())
.callback(new WorkerB())
.param(2)
.build();
// Task C
WorkerWrapper wrapperC = new WorkerWrapper.Builder<Integer, Integer>()
.id("workerC")
.worker(new WorkerC())
.callback(new WorkerC())
.param(3)
.build();
Async.beginWork(1000, wrapperA, wrapperB, wrapperC);Blocking Wait – Serial then Parallel
Execute task A first, then run B and C in parallel.
// Task A
WorkerWrapper wrapperA = new WorkerWrapper.Builder<Integer, Integer>()
.id("workerA")
.worker(new WorkerA())
.callback(new WorkerA())
.param(1)
.build();
// Task B depends on A
WorkerWrapper wrapperB = new WorkerWrapper.Builder<Integer, Integer>()
.id("workerB")
.worker(new WorkerB())
.callback(new WorkerB())
.param(2)
.depend(wrapperA)
.build();
// Task C depends on A
WorkerWrapper wrapperC = new WorkerWrapper.Builder<Integer, Integer>()
.id("workerC")
.worker(new WorkerC())
.callback(new WorkerC())
.param(3)
.depend(wrapperA)
.build();
Async.beginWork(1000, wrapperA);Blocking Wait – Parallel then Serial
Run B and C in parallel first, then execute A after they finish.
// Task A (receives results of B and C)
WorkerWrapper wrapperA = new WorkerWrapper.Builder<Integer, Integer>()
.id("workerA")
.worker(new WorkerA())
.callback(new WorkerA())
.param(null) // will receive results of B and C
.build();
// Task B
WorkerWrapper wrapperB = new WorkerWrapper.Builder<Integer, Integer>()
.id("workerB")
.worker(new WorkerB())
.callback(new WorkerB())
.param(2)
.next(wrapperA)
.build();
// Task C
WorkerWrapper wrapperC = new WorkerWrapper.Builder<Integer, Integer>()
.id("workerC")
.worker(new WorkerC())
.callback(new WorkerC())
.param(3)
.next(wrapperA)
.build();
Async.beginWork(1000, wrapperB, wrapperC);Main Features
Task Orchestration
Supports arbitrary combinations of parallel and serial tasks, allowing developers to define execution order based on business needs.
Execution Monitoring and Callbacks
Every task triggers a callback regardless of success, failure, timeout, or exception, enabling real‑time monitoring. Skipped tasks also invoke callbacks for logging or error handling.
Exception Handling and Fault Tolerance
Each task can specify a timeout and a default return value; failures of independent tasks do not affect others, while upstream failures propagate to dependent tasks.
Performance Optimizations
Low‑thread design reduces thread creation overhead, and the framework is lock‑free, improving concurrency performance.
Result Management
After execution, results can be returned in the order tasks were added, and the whole task group also supports asynchronous callbacks to avoid blocking the main thread.
Thread Pool Management
Thread pools can be shared across all task groups or dedicated to a specific group, offering flexible resource allocation.
Simplified Development
asyncTool encapsulates complex concurrency logic, letting developers focus on business code without deep knowledge of low‑level threading mechanisms.
Precautions
Thread safety: Tasks may run on multiple threads concurrently; ensure they are thread‑safe.
Exception handling: Properly handle exceptions to avoid affecting the whole application.
Timeout configuration: Set reasonable timeouts to prevent resource waste.
Dependency configuration: Correctly define task dependencies to guarantee the intended execution order.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Java Tech Enthusiast
Sharing computer programming language knowledge, focusing on Java fundamentals, data structures, related tools, Spring Cloud, IntelliJ IDEA... Book giveaways, red‑packet rewards and other perks await!
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
