Master Spring Boot Async: Build a Custom ThreadPool for Precise Concurrency Control

This tutorial shows how to replace the default Spring Boot @Async executor with a custom ThreadPoolTaskExecutor, explains each pool parameter, demonstrates annotating async methods to use the pool, and provides a unit test that verifies the thread naming and execution behavior.

Programmer DD
Programmer DD
Programmer DD
Master Spring Boot Async: Build a Custom ThreadPool for Precise Concurrency Control
Spring Boot’s @Async annotation enables asynchronous method execution, but controlling the number of concurrent tasks requires a custom thread pool.

Define a custom ThreadPoolTaskExecutor

Create a configuration class that enables async processing and declares a bean named taskExecutor:

@EnableAsync
@Configuration
public class TaskPoolConfig {
    @Bean("taskExecutor")
    public Executor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(10);            // threads created at startup
        executor.setMaxPoolSize(20);             // additional threads when the queue is full
        executor.setQueueCapacity(200);           // pending task buffer
        executor.setKeepAliveSeconds(60);       // idle thread timeout
        executor.setThreadNamePrefix("taskExecutor-"); // for easier log tracing
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        return executor;
    }
}

Key pool parameters explained

Core pool size 10 – number of threads created when the application starts.

Maximum pool size 20 – extra threads are created only after the queue reaches its capacity.

Queue capacity 200 – buffer for tasks waiting to be executed.

Keep‑alive 60 s – idle threads beyond the core size are terminated after this period.

Thread name prefix – makes log output easier to trace (e.g., taskExecutor-1).

Rejected‑execution policy – CallerRunsPolicy runs the rejected task in the calling thread when the pool is saturated.

Use the custom pool in async methods

Annotate each asynchronous method with the bean name to force execution in the defined pool:

@Slf4j
@Component
public class Task {
    private static final Random random = new Random();

    @Async("taskExecutor")
    public void doTaskOne() throws Exception {
        log.info("Start task one");
        long start = System.currentTimeMillis();
        Thread.sleep(random.nextInt(10000));
        long end = System.currentTimeMillis();
        log.info("Task one finished, cost: {} ms", (end - start));
    }

    @Async("taskExecutor")
    public void doTaskTwo() throws Exception {
        log.info("Start task two");
        long start = System.currentTimeMillis();
        Thread.sleep(random.nextInt(10000));
        long end = System.currentTimeMillis();
        log.info("Task two finished, cost: {} ms", (end - start));
    }

    @Async("taskExecutor")
    public void doTaskThree() throws Exception {
        log.info("Start task three");
        long start = System.currentTimeMillis();
        Thread.sleep(random.nextInt(10000));
        long end = System.currentTimeMillis();
        log.info("Task three finished, cost: {} ms", (end - start));
    }
}

Unit test to verify the configuration

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class ApplicationTests {
    @Autowired
    private Task task;

    @Test
    public void test() throws Exception {
        task.doTaskOne();
        task.doTaskTwo();
        task.doTaskThree();
        // Wait for async tasks to finish
        Thread.currentThread().join();
    }
}

Verification

Running the test prints log lines whose thread names start with taskExecutor-, confirming that the asynchronous methods are executed by the custom thread pool.

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.

JavaconcurrencyThreadPoolSpring BootUnit TestAsync
Programmer DD
Written by

Programmer DD

A tinkering programmer and author of "Spring Cloud Microservices in Action"

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.