Master AsyncTask Orchestration in Spring Boot with asyncTool

This guide explains how to integrate asyncTool into a Spring Boot project, configure custom thread pools, understand core interfaces like IWorker and ICallback, and implement serial, parallel, and mixed task flows with detailed code examples and best‑practice considerations.

Architect's Guide
Architect's Guide
Architect's Guide
Master AsyncTask Orchestration in Spring Boot with asyncTool

Integration into Spring Boot

Add the asyncTool dependency to pom.xml:

<dependency>
    <groupId>com.jd.platform</groupId>
    <artifactId>asyncTool</artifactId>
    <version>YOUR_VERSION</version>
</dependency>

Configure a thread pool. Although asyncTool manages a pool internally, you can define a custom one for finer control. Two approaches are shown:

1) 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
        executor.setThreadNamePrefix("MyExecutor-"); // name prefix
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); // rejection policy
        executor.initialize();
        return executor;
    }
}

2) Override Spring's Native Async Pool

@Configuration
@EnableAsync
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 API Overview

IWorker Interface

action(T object, Map<String, WorkerWrapper> allWrappers)

: Executes the 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)

: Called after execution; success indicates outcome, param is the input, and workResult holds the result.

WorkerWrapper Class

id

: Unique identifier of the task. param: Input parameter. worker: Concrete implementation of IWorker. callback: Implementation of ICallback. depend: Declares strong dependencies that enforce execution order. next: Declares subsequent tasks for flexible sequencing.

Detailed Usage and Examples

1. 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);

2. Parallel Tasks

Multiple tasks run concurrently.

// Define three independent tasks
WorkerWrapper wrapperA = new WorkerWrapper.Builder<Integer, Integer>()…build();
WorkerWrapper wrapperB = new WorkerWrapper.Builder<Integer, Integer>()…build();
WorkerWrapper wrapperC = new WorkerWrapper.Builder<Integer, Integer>()…build();

Async.beginWork(1000, wrapperA, wrapperB, wrapperC);

3. Block‑Wait: Serial then Parallel

Execute A first, then run B and C in parallel.

// A
WorkerWrapper wrapperA = …build();
// B depends on A
WorkerWrapper wrapperB = new WorkerWrapper.Builder<Integer, Integer>()
        .depend(wrapperA)
        .build();
// C depends on A
WorkerWrapper wrapperC = new WorkerWrapper.Builder<Integer, Integer>()
        .depend(wrapperA)
        .build();

Async.beginWork(1000, wrapperA);

4. Block‑Wait: Parallel then Serial

B and C run together; after they finish, A runs.

// A will receive results of B and C
WorkerWrapper wrapperA = new WorkerWrapper.Builder<Integer, Integer>()
        .param(null)
        .build();

WorkerWrapper wrapperB = new WorkerWrapper.Builder<Integer, Integer>()
        .next(wrapperA)
        .build();

WorkerWrapper wrapperC = new WorkerWrapper.Builder<Integer, Integer>()
        .next(wrapperA)
        .build();

Async.beginWork(1000, wrapperB, wrapperC);

Key Benefits

1. Task Orchestration

asyncTool enables flexible combinations of parallel and serial execution, allowing developers to model complex business workflows.

2. Dependency Management

Both strong and weak dependencies can be expressed, ensuring correct ordering while permitting concurrent execution where possible.

3. Monitoring & Callbacks

Every task triggers callbacks for success, failure, timeout, or being skipped, giving real‑time visibility into the execution chain.

4. Exception Handling & Fault Tolerance

Tasks can define timeout thresholds and default return values; isolated failures do not cascade unless upstream dependencies also fail.

5. Performance Optimizations

Low‑thread design reuses threads across dependent tasks, and the framework operates without locks, reducing contention and improving throughput.

6. Result Management

Results can be returned in the order tasks were added, and the whole task group supports asynchronous callbacks to avoid blocking the main thread.

7. Thread‑Pool Flexibility

Each task group may have a dedicated pool or share a common pool, giving fine‑grained resource control.

8. Simplified Development

Complex concurrency logic is encapsulated, letting developers focus on business code rather than low‑level thread handling.

Precautions

Thread Safety : Ensure that task implementations are safe for concurrent execution.

Exception Handling : Properly catch and handle exceptions inside tasks to prevent unexpected termination.

Timeout Configuration : Set reasonable timeouts to avoid resource waste.

Dependency Configuration : Accurately define dependencies to achieve the intended execution order.

By following the steps and guidelines above, you can effectively use asyncTool in a Spring Boot application to orchestrate complex multi‑threaded workflows.

JavaconcurrencySpring BootThread Pooltask orchestrationasyncTool
Architect's Guide
Written by

Architect's Guide

Dedicated to sharing programmer-architect skills—Java backend, system, microservice, and distributed architectures—to help you become a senior architect.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.