When Should You Actually Add a Thread Pool? Insights from Real‑World SpringBoot/Dubbo Projects
This article explores why many developers rarely use thread pools, demonstrates a SpringBoot‑Dubbo demo to reveal hidden thread pools in web containers and RPC frameworks, and offers practical guidance on when to tune existing pools versus adding custom ones for optimal performance.
Recently I saw a developer complain that after three years of work he had never used multithreading. Although he knows the theory, his business code rarely touches thread pools, leading to confusion.
My view is that you must understand thread pools deeply, but in typical business code you should use them sparingly or not at all.
Demo
We quickly set up a demo using an existing Dubbo example that includes both consumer and provider modules.
The demo follows the official quick‑start steps from the Apache Dubbo site.
In this demo we added an HTTP endpoint on the consumer side to trigger an RPC call, mimicking a front‑end request.
When the demo runs, the console shows logs from both provider and consumer, confirming the call works.
Where Are the Thread Pools?
Looking at the consumer code and provider code (shown in the diagrams), there is no explicit thread‑pool code in the business logic.
However, the HTTP request is handled by a web container (Tomcat, Jetty, Netty, etc.), which uses its own thread pool. The thread named
http-nio-8081-exec-1is a Tomcat pool thread.
Dumping the thread stack reveals about ten idle threads from the container pool, confirming its existence.
Similarly, Dubbo itself employs multiple thread pools (I/O pool, business pool, etc.) to isolate resources.
Performance Tuning vs. Adding Custom Pools
When service throughput is low, adding a custom thread pool in business code may seem tempting, but the web container and framework already provide configurable pools.
Adjusting Tomcat’s executor settings or Dubbo’s thread‑pool parameters yields better results than inserting another pool.
Moreover, adding a pool can backfire: it may increase upstream load, causing downstream services to become bottlenecks.
In such cases, using a message queue for asynchronous processing or coordinating with downstream services is safer.
When to Use a Thread Pool
Thread pools are appropriate when a request must invoke several independent services in parallel, converting serial work into concurrent execution.
They are also useful for scheduled jobs that fetch a batch of records and need to query downstream services concurrently.
<code>// Example: processing a list of orders sequentially
ArrayList initOrderInfoList = queryInitOrderInfoList();
for (OrderInfo orderInfo : initOrderInfoList) {
try {
String orderStatus = queryOrderStatus(orderInfo.getOrderId);
updateOrderInfo(orderInfo.getOrderId, orderStatus);
} catch (Exception e) {
// handle exception
}
}
</code>To speed up such batch processing, you can introduce a thread pool inside the loop:
<code>// Using a thread pool for concurrent processing
for (OrderInfo orderInfo : initOrderInfoList) {
executor.execute(() -> {
try {
String orderStatus = queryOrderStatus(orderInfo.getOrderId);
updateOrderInfo(orderInfo.getOrderId, orderStatus);
} catch (Exception e) {
// handle exception
}
});
}
</code>Choosing appropriate pool parameters and understanding its role—similar to the web container pool—is essential for achieving optimal throughput without overwhelming downstream services.
macrozheng
Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.
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.