Master AsyncTask Orchestration in Spring Boot with asyncTool

This guide explains how to integrate the asyncTool library into a Spring Boot project, configure custom thread pools, understand core interfaces like IWorker and ICallback, and use the provided Builder API to define serial, parallel, and mixed task flows with detailed code examples and best‑practice cautions.

Java Architect Handbook
Java Architect Handbook
Java Architect Handbook
Master AsyncTask Orchestration in Spring Boot with asyncTool

Integration with Spring Boot

Add the asyncTool dependency to pom.xml:

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

Although asyncTool manages its own thread pool, you can provide a custom pool for finer control. Two configuration approaches are available.

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 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 API

IWorker interface

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

: business 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()

: invoked when the task starts.

result(boolean success, T param, WorkResult<V> workResult)

: receives the execution outcome; success indicates success, param is the input, and 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 dependencies to enforce execution order. next: defines subsequent tasks for flexible sequencing.

Usage examples

Serial tasks

// Define task A
WorkerWrapper wrapperA = new WorkerWrapper.Builder<Integer, Integer>()
        .id("workerA")
        .worker(new WorkerA())
        .callback(new WorkerA())
        .param(1)
        .build();

// Define 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();

// Define 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();

// Submit the first task (the chain will follow)
Async.beginWork(1000, wrapperA);

Parallel tasks

// Define task A
WorkerWrapper wrapperA = new WorkerWrapper.Builder<Integer, Integer>()
        .id("workerA")
        .worker(new WorkerA())
        .callback(new WorkerA())
        .param(1)
        .build();

// Define task B
WorkerWrapper wrapperB = new WorkerWrapper.Builder<Integer, Integer>()
        .id("workerB")
        .worker(new WorkerB())
        .callback(new WorkerB())
        .param(2)
        .build();

// Define task C
WorkerWrapper wrapperC = new WorkerWrapper.Builder<Integer, Integer>()
        .id("workerC")
        .worker(new WorkerC())
        .callback(new WorkerC())
        .param(3)
        .build();

// Submit all tasks together
Async.beginWork(1000, wrapperA, wrapperB, wrapperC);

Block‑wait – serial then parallel

// Define task A
WorkerWrapper wrapperA = new WorkerWrapper.Builder<Integer, Integer>()
        .id("workerA")
        .worker(new WorkerA())
        .callback(new WorkerA())
        .param(1)
        .build();

// Define 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();

// Define task C, also 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);

Block‑wait – parallel then serial

// Define 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)
        .build();

// Define task B
WorkerWrapper wrapperB = new WorkerWrapper.Builder<Integer, Integer>()
        .id("workerB")
        .worker(new WorkerB())
        .callback(new WorkerB())
        .param(2)
        .next(wrapperA)
        .build();

// Define 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);

Key benefits

Task orchestration : combine any number of serial and parallel tasks to match business requirements.

Dependency management : support strong and weak dependencies, allowing tasks to wait for specific predecessors.

Execution monitoring & callbacks : each task triggers callbacks on start, success, failure, timeout, or exception, enabling real‑time monitoring.

Exception handling & fault tolerance : configurable timeout and default return values keep the overall chain stable; a failed upstream task propagates failure to dependent tasks.

Performance optimization : low‑thread design reduces thread creation overhead; the framework is lock‑free for higher concurrency.

Result management : results can be returned in the order tasks were added, and the whole task group also supports asynchronous callbacks.

Thread‑pool management : each task group can use a dedicated pool or share a common pool, offering flexible resource allocation.

Simplified development : complex concurrency logic is encapsulated, letting developers focus on business code.

Precautions

Ensure task implementations are thread‑safe because they may run on multiple threads.

Handle exceptions inside tasks to avoid cascading failures.

Set reasonable timeout values to prevent resource waste.

Configure dependency relationships correctly so tasks execute in the intended order.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaBackend DevelopmentconcurrencySpring BootThread Pooltask orchestrationasyncTool
Java Architect Handbook
Written by

Java Architect Handbook

Focused on Java interview questions and practical article sharing, covering algorithms, databases, Spring Boot, microservices, high concurrency, JVM, Docker containers, and ELK-related knowledge. Looking forward to progressing together with you.

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.