Backend Development 11 min read

Implementing a Dynamic Thread Pool with Nacos in Spring Boot

This article demonstrates how to create a dynamically configurable thread pool in a Spring Boot backend by using Nacos as a configuration center, covering Maven dependencies, YAML configuration files, Nacos data IDs, Java implementation with listeners, a REST controller for testing, and practical verification steps.

Code Ape Tech Column
Code Ape Tech Column
Code Ape Tech Column
Implementing a Dynamic Thread Pool with Nacos in Spring Boot

Hello everyone, I am Chen.

In backend development, thread pools are frequently used, but configuring core parameters often relies on experience and requires service restarts, which is costly. Placing thread‑pool settings on a platform side and allowing developers to adjust them dynamically based on runtime conditions can solve this problem.

This article uses Nacos as a service configuration center and shows, through modifying the core and maximum thread numbers, how to implement a simple dynamic thread pool.

Code Implementation

1. Dependencies

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    <version>2021.1</version>
</dependency>
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
    <version>2021.1</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
</dependency>

2. Configure YML files

bootstrap.yml:

server:
  port: 8010
  # Application name (Nacos treats this as the service name)
spring:
  application:
    name: order-service
  cloud:
    nacos:
      discovery:
        namespace: public
        server-addr: 192.168.174.129:8848
      config:
        server-addr: 192.168.174.129:8848
        file-extension: yml

application.yml:

spring:
  profiles:
    active: dev

Why two YML files? In Spring Boot the loading order gives bootstrap higher priority than application . Nacos must fetch configuration from the config center before the application starts, so the bootstrap file ensures early loading.

3. Nacos configuration

Log in to the Nacos console and create a new configuration (see image). The Data ID follows the pattern ${spring.application.name}-${spring.profile.active}.${spring.cloud.nacos.config.file-extension} , which in this article becomes order-service-dev.yml . Only two parameters – core thread count and maximum thread count – are configured.

4. Thread‑pool configuration and Nacos change listener

@RefreshScope
@Configuration
public class DynamicThreadPool implements InitializingBean {
    @Value("${core.size}")
    private String coreSize;

    @Value("${max.size}")
    private String maxSize;

    private static ThreadPoolExecutor threadPoolExecutor;

    @Autowired
    private NacosConfigManager nacosConfigManager;

    @Autowired
    private NacosConfigProperties nacosConfigProperties;

    @Override
    public void afterPropertiesSet() throws Exception {
        // Initialize thread pool according to Nacos config
        threadPoolExecutor = new ThreadPoolExecutor(Integer.parseInt(coreSize), Integer.parseInt(maxSize), 10L, TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(10),
                new ThreadFactoryBuilder().setNameFormat("c_t_%d").build(),
                new RejectedExecutionHandler() {
                    @Override
                    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
                        System.out.println("rejected!");
                    }
                });

        // Nacos config change listener
        nacosConfigManager.getConfigService().addListener("order-service-dev.yml", nacosConfigProperties.getGroup(),
                new Listener() {
                    @Override
                    public Executor getExecutor() {
                        return null;
                    }

                    @Override
                    public void receiveConfigInfo(String configInfo) {
                        // Config changed, update thread pool
                        System.out.println(configInfo);
                        changeThreadPoolConfig(Integer.parseInt(coreSize), Integer.parseInt(maxSize));
                    }
                });
    }

    /** Print current thread‑pool status */
    public String printThreadPoolStatus() {
        return String.format("core_size:%s,thread_current_size:%s;thread_max_size:%s;queue_current_size:%s,total_task_count:%s",
                threadPoolExecutor.getCorePoolSize(), threadPoolExecutor.getActiveCount(),
                threadPoolExecutor.getMaximumPoolSize(), threadPoolExecutor.getQueue().size(),
                threadPoolExecutor.getTaskCount());
    }

    /** Add tasks to the thread pool */
    public void dynamicThreadPoolAddTask(int count) {
        for (int i = 0; i < count; i++) {
            int finalI = i;
            threadPoolExecutor.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        System.out.println(finalI);
                        Thread.sleep(10000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
    }

    /** Modify core parameters */
    private void changeThreadPoolConfig(int coreSize, int maxSize) {
        threadPoolExecutor.setCorePoolSize(coreSize);
        threadPoolExecutor.setMaximumPoolSize(maxSize);
    }
}

Key points:

@RefreshScope enables Nacos dynamic refresh.

@Value("${max.size}") and @Value("${core.size}") read the values from Nacos and update them in real time.

nacosConfigManager.getConfigService().addListener listens for configuration changes and adjusts the thread pool accordingly.

5. Controller

A simple REST controller is added to observe the dynamic changes.

@RestController
@RequestMapping("/threadpool")
public class ThreadPoolController {

    @Autowired
    private DynamicThreadPool dynamicThreadPool;

    /** Print current thread‑pool status */
    @GetMapping("/print")
    public String printThreadPoolStatus() {
        return dynamicThreadPool.printThreadPoolStatus();
    }

    /** Add tasks to the thread pool */
    @GetMapping("/add")
    public String dynamicThreadPoolAddTask(int count) {
        dynamicThreadPool.dynamicThreadPoolAddTask(count);
        return String.valueOf(count);
    }
}

6. Test

Start the project and visit http://localhost:8010/threadpool/print to see the current thread‑pool configuration (see image).

Call /threadpool/add?count=20 to add 20 tasks and then re‑print the status (see image). You will see tasks queuing.

Repeatedly invoke the /add endpoint; when the console shows rejection messages, adjust the Nacos configuration.

After changing the Nacos values to core=50 and max=100, the rejections disappear and the printed status confirms the new parameters.

Summary

This article provides a straightforward implementation of a dynamic thread pool whose core and maximum thread numbers can be adjusted at runtime via Nacos. For deeper insights into thread‑pool design, refer to Meituan’s article (https://tech.meituan.com/2020/04/02/java-pooling-pratice-in-meituan.html) and consider integrating monitoring and alerting to build a complete dynamic thread‑pool product.

Other excellent solutions exist, such as Hippo4J, which offers both middleware‑free and Nacos/Apollo‑based implementations, while dynamic‑tp defaults to Nacos or Apollo.

Final Note (Please support)

If this article helped you, please like, follow, share, or bookmark – your support keeps me going!

My knowledge‑sharing community is also open for a 199 CNY subscription, offering extensive resources like Spring full‑stack projects, massive data sharding practice, DDD micro‑service series, and more.

For more details, visit the links above.

Javabackend developmentdynamic configurationNacosSpring Bootthread pool
Code Ape Tech Column
Written by

Code Ape Tech Column

Former Ant Group P8 engineer, pure technologist, sharing full‑stack Java, job interview and career advice through a column. Site: java-family.cn

0 followers
Reader feedback

How this landed with the community

login 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.