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.