springboot 自定义线程池后程序无法终止

文章探讨了在SpringBoot应用中自定义线程池与使用默认线程池的区别,特别是在`allowCoreThreadTimeOut`属性上的差异。当`allowCoreThreadTimeOut`设置为`false`时,核心线程不会因无任务而终止,导致应用无法正常关闭。而设置为`true`并配合非零`keepAliveTime`,线程会在指定时间后自动终止。解决方案是调整线程池配置,确保应用能够正确关闭。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

背景

springboot 自定义线程池,并在ComplatedFuture.runAsync(Runnable, Executor)使用该线程池执行任务

@Configuration
public class ExecutorConfig {

    private static final Logger logger = LoggerFactory.getLogger(ExecutorConfig.class);

    @Value("${spring.task.execution.pool.core-size:20}")
    private int corePoolSize;
    @Value("${spring.task.execution.pool.max-size:50}")
    private int maxPoolSize;
    @Value("${spring.task.execution.pool.queue-capacity:100}")
    private int queueCapacity;
    @Value("${spring.task.execution.thread-name-prefix:empf_}")
    private String namePrefix;
    @Value("${spring.task.execution.pool.keep-alive:3}")
    private int keepAliveSeconds;


    @Bean(name = "asyncServiceExecutor")
    public Executor asyncServiceExecutor() {
        logger.info("start asyncServiceExecutor");
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //配置核心线程数
        executor.setCorePoolSize(corePoolSize);
        //配置最大线程数
        executor.setMaxPoolSize(maxPoolSize);
        //配置队列大小
        executor.setQueueCapacity(queueCapacity);
        //配置线程池中的线程的名称前缀
        executor.setThreadNamePrefix(namePrefix);
        executor.setKeepAliveSeconds(keepAliveSeconds);
        executor.setWaitForTasksToCompleteOnShutdown(true);

        // rejection-policy:当pool已经达到max size的时候,如何处理新任务
        // CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        //执行初始化
        executor.initialize();
        return executor;
    }
}

@Service
public class PrintService{
	@Autowired
    private Executor asyncServiceExecutor;
    
	public void printNumber(){
		CompletableFuture.runAsync(() -> System.out.println(1), asyncServiceExecutor);
	}
}

在运行完成程序后,springboot应用并没有结束,而是处于一直等待的状态

而当不使用自动线程池,直接注入springboot的线程池,在运行完printNumber()方法60s后,springboot应用停止

public class PrintService{
	@Autowired
    private Executor executor;
    
	public void printNumber(){
		CompletableFuture.runAsync(() -> System.out.println(1), asyncServiceExecutor);
	}
}

问题探索

因此去查看两个线程池有何差异,其中有一个属性allowCoreThreadTimeOut 不一样,自定义线程池的为false,springboot默认线程池为true

再查看此属性的作用

package java.util.concurrent;

public class ThreadPoolExecutor{
	/**
     * Sets the policy governing whether core threads may time out and
     * terminate if no tasks arrive within the keep-alive time, being
     * replaced if needed when new tasks arrive. When false, core
     * threads are never terminated due to lack of incoming
     * tasks. When true, the same keep-alive policy applying to
     * non-core threads applies also to core threads. To avoid
     * continual thread replacement, the keep-alive time must be
     * greater than zero when setting {@code true}. This method
     * should in general be called before the pool is actively used.
     *
     * @param value {@code true} if should time out, else {@code false}
     * @throws IllegalArgumentException if value is {@code true}
     *         and the current keep-alive time is not greater than zero
     *
     * @since 1.6
     */
	public void allowCoreThreadTimeOut(boolean value) {
        if (value && keepAliveTime <= 0)
            throw new IllegalArgumentException("Core threads must have nonzero keep alive times");
        if (value != allowCoreThreadTimeOut) {
            allowCoreThreadTimeOut = value;
            if (value)
                interruptIdleWorkers();
        }
    }
}

注意这句,When false, core threads are never terminated due to lack of incoming tasks

大意就是,当 allowCoreThreadTimeOut = false 时,即使没有任务执行,核心线程也不会终止,这就可以解释为什么自定义线程池的springboot应用没办法终止

另外注意,When true, the same keep-alive policy applying to non-core threads applies also to core threads. To avoid continual thread replacement, the keep-alive time must be greater than zero when setting true.

当 allowCoreThreadTimeOut = true 时,keep-alive time 需要为正数,经过 keep-alive time 后,线程将就会自动终止

额外收获

springboot线程池创建相关的类

TaskExecutorBuilder
TaskExecutionAutoConfiguration
TaskExecutionProperties
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值