1890 字
约 6 分钟
3
Spring Boot 为什么要使用自定义线程池?一文搞懂线程池的作用

Spring Boot 为什么要使用自定义线程池?一文搞懂线程池的作用

在开发 Spring Boot 项目时,我们经常会遇到一些耗时但不影响主业务的操作,例如:

  • 发送邮件
  • 发送短信
  • 阅读量统计
  • 操作日志记录
  • 用户行为统计
  • 消息通知

很多同学第一反应就是开启一个线程去执行:

new Thread(() -> {
    // 执行耗时任务
}).start();

功能虽然可以实现,但在实际项目中,这种写法并不推荐。

那么,为什么 Spring 官方更推荐使用线程池?又为什么很多项目都会配置自定义线程池

本文带你一步一步理解。


一、什么是线程?

线程(Thread)是程序执行的最小单位。

一个应用程序启动后,会创建一个进程,而一个进程中可以包含多个线程。

例如浏览器:

Chrome
│
├── 页面渲染线程
├── JavaScript线程
├── 网络请求线程
├── GPU线程
└── 定时器线程

多个线程可以同时执行不同的任务,因此能够提高程序的并发能力。


二、为什么要使用线程?

假设有一个接口:

@GetMapping("/article/{id}")
public ArticleVO detail(Long id){
    return articleService.detail(id);
}

除了查询文章之外,还需要:

  • 阅读量 +1
  • 保存阅读历史
  • 记录访问日志

如果全部同步执行:

查询文章
    ↓
更新阅读量
    ↓
记录日志
    ↓
保存历史
    ↓
返回页面

用户必须等待所有任务执行完成。

实际上:

用户真正关心的是:

尽快看到文章内容。

而阅读量统计、日志记录等业务完全可以放到后台执行。

这就是线程存在的意义。

主线程负责处理核心业务。

后台线程负责处理耗时任务。

整个接口响应速度会更快。


三、为什么不能一直 new Thread()?

很多初学者都会这样写:

new Thread(() -> {

    sendMail();

}).start();

如果只是偶尔执行一次,问题不大。

但是如果网站一天有几万甚至几十万次请求:

10000 个请求

↓

10000 个 Thread

系统就需要不断地:

创建线程

↓

执行任务

↓

销毁线程

线程的创建和销毁都需要消耗系统资源。

大量线程甚至可能导致:

  • CPU 使用率过高
  • 内存占用增加
  • 上下文切换频繁
  • 系统响应变慢

因此,大型项目几乎不会频繁创建线程。


四、什么是线程池?

线程池(Thread Pool)可以理解为:

提前准备好一批线程,需要执行任务时直接拿来使用。

例如线程池中提前创建了四个线程:

Thread-1

Thread-2

Thread-3

Thread-4

当任务到来时:

任务1 → Thread-1

任务2 → Thread-2

任务3 → Thread-3

任务4 → Thread-4

如果线程都在忙:

任务5

↓

进入等待队列

等有线程空闲后,再继续执行。

线程不会反复创建,而是不断复用。


五、线程池有什么优势?

1、减少线程创建和销毁开销

线程创建是一项比较昂贵的操作。

线程池通过重复利用已有线程,大大降低了系统开销。


2、提高系统响应速度

线程准备好以后,任务无需等待线程创建。

直接提交即可执行。

因此整体响应速度更快。


3、统一管理线程数量

线程池可以限制:

  • 核心线程数
  • 最大线程数

避免因为线程无限增长导致服务器资源耗尽。

例如:

最大线程数:8

即使同时来了 1000 个任务,也不会创建 1000 个线程。


4、提供任务等待队列

当线程全部处于忙碌状态时:

新的任务不会立即丢失。

而是进入等待队列:

任务

↓

BlockingQueue

↓

等待线程执行

当然,如果:

  • 队列满了
  • 最大线程也满了

新的任务就会触发线程池的拒绝策略。

因此线程池参数需要根据业务合理配置。


六、为什么要使用自定义线程池?

Spring Boot 默认也提供了线程池。

但是实际开发中,通常不会所有业务共用一个线程池。

例如:

发送邮件

阅读量统计

图片压缩

AI生成内容

短信发送

如果全部使用同一个线程池:

某个业务大量占用线程之后,其它业务都会受到影响。

因此一般都会按照业务划分线程池。

例如:

articleThreadPool

mailThreadPool

logThreadPool

imageThreadPool

这样即使:

邮件发送出现大量积压

也不会影响:

文章阅读量统计

业务之间互不影响。


七、Spring Boot 配置自定义线程池

Spring Boot 推荐使用 ThreadPoolTaskExecutor

例如:

@Configuration
@EnableAsync
public class ThreadPoolConfig {

    @Bean("articleThreadPool")
    public Executor articleThreadPool() {

        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();

        // 核心线程数
        executor.setCorePoolSize(4);

        // 最大线程数
        executor.setMaxPoolSize(8);

        // 队列容量
        executor.setQueueCapacity(100);

        // 线程名称前缀
        executor.setThreadNamePrefix("article-");

        executor.initialize();

        return executor;
    }

}

随后在需要异步执行的方法上指定线程池:

@Async("articleThreadPool")
public void increaseReadCount(Long articleId){

    // 阅读量 +1

}

这样,Spring 就会自动将该任务提交到指定线程池执行。


八、什么时候适合使用线程池?

线程池比较适合处理:

  • 阅读量统计
  • 登录日志
  • 操作日志
  • 消息通知
  • 邮件发送
  • 短信发送
  • 文件上传
  • 图片压缩
  • Excel 导入导出

这些任务有一个共同特点:

不是用户必须立即得到结果。

因此可以放到后台执行,提高接口响应速度。


九、什么时候不建议异步?

如果业务之间存在强依赖关系,就不要异步。

例如:

创建订单

↓

扣减库存

↓

支付

↓

返回成功

如果库存扣减失败,订单就不能继续创建。

这类核心业务流程应该同步执行,保证数据一致性。


十、总结

线程并不是为了让代码"看起来高级",而是为了让耗时任务不阻塞主业务

相比频繁创建线程,线程池能够:

  • 重复利用线程,降低资源开销;
  • 控制并发数量,避免服务器资源耗尽;
  • 提供任务队列,提高系统稳定性;
  • 统一管理线程,方便维护。

在 Spring Boot 项目中,更推荐根据业务划分自定义线程池,而不是所有异步任务共用一个线程池。

例如文章阅读量统计、邮件发送、日志记录等场景,都非常适合交给线程池异步处理。

下一篇文章,我将结合 Spring Event + 自定义线程池,实现一个更加解耦的文章阅读量异步统计功能。

Spring Boot 为什么要使用自定义线程池?一文搞懂线程池的作用
http://clxhxhhr.top/posts/387/
作者
clxstart
发布于
2026-09-01
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。