SpringBoot中持续复用的ExecutorService是否需要调用shutdown?
关于SpringBoot中ExecutorService复用与关闭的问题
我有一个SpringBoot应用,每24小时会通过API触发一次任务,任务在独立线程中执行,耗时较短,之后应用就处于空闲状态,直到次日再次触发。示例代码如下:
private ExecutorService es = Executors.newFixedThreadPool(2); @PostMapping public void startTest(@RequestBody DummyModel dummy) throws InterruptedException { int i = 0; while(i<3) { es.execute(new ListProcessing(dummy)); es.execute(new AnotherListProcessing(dummy)); i++; } // 因为方法是异步的,此代码会在任务完成前立即执行 }
如你所见,while循环结束后我没有调用es.shutdown()。很多文章和讨论都强调任务完成后调用.shutdown()的重要性,但如果在这里添加这个方法,下一次POST请求就会报错(这符合预期,因为.shutdown()会在现有任务完成后拒绝新任务)。
我想搞清楚几个问题:
- 此处是否真的需要调用
shutdown()? - 我的应用每天接收一次POST请求,ExecutorService会被频繁复用,长期不关闭它有什么弊端吗?
- 如果确实需要每次使用后都关闭,该如何操作才能让应用在次日准备好接收新请求?
我曾考虑在while循环后添加以下代码:
es.shutdown(); es = Executors.newFixedThreadPool(2);
这能正常运行,但我觉得:
a) 完全没必要——为什么要关闭后再重新创建,纯粹浪费资源
b) 这种做法不太合理,肯定有更优的方案
更新思路
最初我想到两种方案,但都不太满意:
- 自定义
ThreadPoolExecutor:对我的简单场景来说有点小题大做 - 使用CachedThreadPool:它会尝试创建尽可能多的线程,不符合我需要固定数量线程的需求
最终实现方案
按照Thomas和Deinum的建议,我们可以使用Spring提供的自定义配置的Executor,它具备ExecutorService的功能,还能自动清理,配置也很简便。以下是我的实现:
Controller代码
@Autowired private TaskExecutor taskExecutor; @PostMapping public void startTest(@RequestBody DummyModel dummy) throws InterruptedException { taskExecutor.execute(new ProcessList()); taskExecutor.execute(new AnotherProcessList()); taskExecutor.execute(new YetAnotherProcessList()); }
配置Bean
在主类或任何带有@Configuration注解的类中定义TaskExecutor Bean:
@Bean public TaskExecutor taskExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(5); // 始终保持的最小线程数 executor.setMaxPoolSize(10); // 线程池满且队列满时,会创建额外线程 executor.setQueueCapacity(5); // 待执行任务的队列容量(注意队列占用内存,队列越大内存占用越多) return executor; }
内容的提问来源于stack exchange,提问作者Joe
相关产品推荐
相关产品推荐

